一、创建线程方式
a. 继承线程类( new Thread),重写run方法;
public class MyThread extends Thread{//继承Thread类 public void run(){ //重写run方法 } } public class Main { public static void main(String[] args){ new MyThread().start();//创建并启动线程 } }
b. 实现runnable接口,将runnable对象传入Thread类;
public class MyThread2 implements Runnable {//实现Runnable接口 public void run(){ //重写run方法 } } public class Main { public static void main(String[] args){ //创建并启动线程 MyThread2 myThread=new MyThread2(); Thread thread=new Thread(myThread); thread().start(); //或者 new Thread(new MyThread2()).start(); } }
c. 使用线程池的方式,提交runnable或callable任务;
public class Main { public static void main(String[] args){ MyThread3 th=new MyThread3(); //使用Lambda表达式创建Callable对象 //使用FutureTask类来包装Callable对象 FutureTask<Integer> future=new FutureTask<Integer>( (Callable<Integer>)()->{ return 5; } ); new Thread(task,"有返回值的线程").start();//实质上还是以Callable对象来创建并启动线程 try{ System.out.println("子线程的返回值:"+future.get());//get()方法会阻塞,直到子线程执行结束才返回 }catch(Exception e){ ex.printStackTrace(); } } }
d. 推荐使用第三种方式。高效,资源可控;
二、什么是线程同步?线程同步什么时候用?
1)什么是线程同步;
即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态;
2)线程同步在什么时候用(卖火车票,飞机票,取钱);
简单的说,同步就是防止多个线程访问同一个对象,造成数据不安全;线程的同步意味安全,譬如你去取钱 ,你的执行语句和我用的要是相同对象 ,你要在卡上扣除的钱数和银行卡里面要有这么多钱才能扣除;
三、什么是线程安全;
1)所谓线程安全,是多个线程并发执行的情况下结果总是跟单线程运行的结果一致,逻辑上不会出现错误;
2)什么情况下会出现线程安全问题?
多个线程同时操作同一份数据,常常会导致线程安全问题。比如:全局的变量,静态变量,同一条数据的数据库操作等;
局部变量,通常不会存在线程安全问题。
3)常见的解决线程安全的方式:
1)避免使用全局的变量,将全局的变量定义为局部变量。
2)加同步锁,使得线程同步。
a. Synchronized 同步关键字,可以加在方法和代码块上面;
/** * synchronized添加到方法上面,使方法变成同步方法 * 如果是静态方法,锁住的是class * 如果是普通方法,锁住的this,当前对象 synchronized(this) * 多个线程锁住的对象是同一个对象才能够同步,每个类都有当前对象 */ public static synchronized void salTicket(){ if (ticketNum > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "买到第" + ticketNum-- + "张票"); System.out.println(Thread.currentThread().getName() + "买票完成"); }else { System.out.println("票已经售完,"+Thread.currentThread().getName() + "未买到票"); } }
b. 多个线程方法是否同步,需要判断多个线程是否共用同一把锁;
/** * 同步代码块 */ public void salTicket2() { synchronized (this) { //()中指定锁对象,this表示当前对象,多个线程使用同一个对象调用该方法时,是同步的 //如果指定为 class,则该类的任意对象调用该方法都是同步的 if (ticketNum > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "买到第" + ticketNum-- + "张票"); System.out.println(Thread.currentThread().getName() + "买票完成"); } else { System.out.println("票已经售完," + Thread.currentThread().getName() + "未买到票"); } } }
c. ReentrantLock 对象的lock 方法进行加锁,unLock进行解锁。Unlock必须放在finally中。确保能够最终释放锁;
//锁对象 private static ReentrantLock lock=new ReentrantLock(); /** * 使用lock对象进行同步,多个线程使用的是同一个lock对象,才会是同步的 */ public void salTicket3() { lock.lock();//加锁 if (ticketNum > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock();//释放锁,必须放在finally代码块中,以确保能够释放锁 } System.out.println(Thread.currentThread().getName() + "买到第" + ticketNum-- + "张票"); System.out.println(Thread.currentThread().getName() + "买票完成"); } else { System.out.println("票已经售完," + Thread.currentThread().getName() + "未买到票"); } }
3)数据库操作的话,也可以使用乐观锁或悲观锁的方式
4)Springmvc是如何解决线程安全问题的?
Springmvc的数据接收和传递都是方法级别的,使用局部变量来接收和传递,所以不存在线程安全问题。
四、Wait 和notify
线程间通讯的一种机制。用于手动控制线程之间的切换。在同步代码中的锁对象调用。可以同时通过共享内存对象,来实现数据的传递;
3)多线程实现,怎么用?
a、将单个大的任务拆分成多个小任务,使用多线程去执行;
多线程的效率不一定比单线程的效率高;
通过线程池创建线程,通过实现runnable(无返回值)或callable(有返回值)接口来定义任务;
通过线程池的submit invoke invokeAll 等方法来执行任务;
b、使用线程异步完成某些任务,提高并发响应的能力,或让线程周期性的执行某些任务;
c、四种线程池的特点及其创建;
Java通过Executors提供四种线程池,分别为:
1)newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
2)newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
3)newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
4)newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
//jdk中提供的四种快速创建线程池的方式 //1.定长线程池 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10); //2.缓存线程池 ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); //3.周期线程池,可用来实现定时任务 ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10); //4.单线程线程池 ExecutorService executorService = Executors.newSingleThreadExecutor();
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。
今天面试遇到个场景题,复盘的时候想了许久,也没想明白。 场景: 一个线程,通过Runnable接口,重写run方法,方法内部是: run(){ while(true){ "打印中xxx" sleep(10s) } } 场景解析,假设本地idea启动,我需要10S内 中断这个线程,怎么优化这个代码。比如在控台输入 "wq" 立马结束打印线程。 有什么思路?#23届找工作求助阵地##
本文向大家介绍python线程中的同步问题及解决方法,包括了python线程中的同步问题及解决方法的使用技巧和注意事项,需要的朋友参考一下 多线程开发可能遇到的问题 假设两个线程t1和t2都要对num=0进行增1运算,t1和t2都各对num修改1000000次,num的最终的结果应该为2000000。但是由于是多线程访问,有可能出现下面情况: 运行结果可能不一样,但是结果往往不是2000000。问
主要内容:1.缓存穿透,2.缓存击穿,3.缓存雪崩缓存穿透 缓存击穿 缓存雪崩 1.缓存穿透 缓存穿透指的是一个缓存系统无法缓存某个查询的数据,从而导致这个查询每一次都要访问数据库。 常见的Redis缓存穿透场景包括: 查询一个不存在的数据:攻击者可能会发送一些无效的查询来触发缓存穿透。 查询一些非常热门的数据:如果一个数据被访问的非常频繁,那么可能会导致缓存系统无法处理这些请求,从而造成缓存穿透。 查询一些异常数据:这种情况通常发生在数据服务出
Java 语言通过 synchronized 关键字来保证原子性,这是因为每一个 Object 都有一个隐含的锁,这个也称作监视器对象。在进入 synchronized 之前自动获取此内部锁,而一旦离开此方式,无论是完成或者中断都会自动释放锁。显然这是一个独占锁,每个锁请求之间是互斥的。相对于众多高级锁 (Lock/ReadWriteLock 等),synchronized 的代价都比后者要高。但
本文向大家介绍Java多线程的临界资源问题解决方案,包括了Java多线程的临界资源问题解决方案的使用技巧和注意事项,需要的朋友参考一下 这篇文章主要介绍了Java多线程的临界资源问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 临界资源问题的原因:某一个线程在对临界资源进行访问时,还没来得及完全修改临界资源的值,临界资源就被其他线程拿去
本文向大家介绍解决PySide+Python子线程更新UI线程的问题,包括了解决PySide+Python子线程更新UI线程的问题的使用技巧和注意事项,需要的朋友参考一下 在我开发的系统,需要子线程去运行,然后把运行的结果发给UI线程,让UI线程知道运行的进度。 首先创建线程很简单 之后我发现用子线程去调用UI线程是行不通的,只能通过信号和槽来实现,于是 首先,定义一个类,让他实现PySide.Q