并发
线程池
核心数量满时,陷入队列,再入非核心,
io密集式线程池线程数量为cup2
cpu密集时线程池数量为cpu核数
*进程与线程
进程是一个具有一定独立功能的程序,是操作系统动态执行的基本单元。
线程是操作系统能够进行运算的最小单位,它被包含在进程中。
实现多线程两种方法
继承Thread倾向于多个线程完成各自任务,实现Runnable倾向于多个线程完成一个任务(由其statr方法决定)
多线程中代码执行顺序与调用顺序无关
要使用p.start不是run
继承Thread,重写run方法
public class demo { public static void main(String[] args) { PrimeThread p1 = new PrimeThread(1); PrimeThread p2 = new PrimeThread(2); PrimeThread p3 = new PrimeThread(3); PrimeThread p4 = new PrimeThread(4); PrimeThread p5 = new PrimeThread(5); p1.start(); p1.start(); p1.start(); p1.start(); p1.start(); System.out.println("完成"); } } class PrimeThread extends Thread{ long minPrime; PrimeThread(long minPrime){ this.minPrime = minPrime; } @Override public void run(){ //实际业务代码 System.out.println("val="+minPrime); } }
实现Runnable,重写run方法
public class demo { public static void main(String[] args) { PrimeThread p1 = new PrimeThread(1); Thread thread = new Thread(p1); thread.start(); System.out.println("完成"); } } class PrimeThread implements Runnable{ long val; PrimeThread(long val){ this.val = val; } @Override public void run() { System.out.println("val="+val); } }
设置线程优先级
优先级为1-10 Thread.currentThread().getPriority(8); Thread.currentThread().setPriority(1);
守护线程
当没有用户线程时守护线程会自动销毁,如垃圾回收线程
public class demo1 { public static void main(String[] args) throws InterruptedException { DefendThread defendThread = new DefendThread(); Thread thread = new Thread(defendThread); thread.setDaemon(true);//把线程设置为守护线程 要在start前设置 thread.start(); Thread.sleep(1000); System.out.println("主线程在输出完这一行后就结束了"); } } class DefendThread implements Runnable{ @Override public void run() { while (true){ System.out.println(System.currentTimeMillis()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
线程同步机制
线程同步机制用来解决多线程的线程安全问题
synchronized同步方法
非线程安全就是当多个线程访问同一个成员变量时,可能会产生脏读等问题。
线程安全就是获取的成员变量经过同步处理,不会脏读。
局部变量永远是线程安全的
如果有多个线程同时操作业务对象中的成员变量,可能会出现非线程安全。在方法前加上synchronized关键字能保证线程安全。
synchronized取得的是对象锁,当多个线程同时操作一个对象时,有synchronized标识的方法必须依次执行,不能同时执行。没有synchronized标识的方法,可以同时执行。
锁重入机制,在一个被synchronized修饰的方法中调用另一个被synchronized修饰的方法,可以立即执行,没有必要等到当前方法执行完在执行。
锁的释放机制:当一个线程执行的代码出现异常,它所持有的锁会自动释放
同步不具有继承性
Synchronized同步代码块比synchronized声明方法效率要高。Synchronized(object){}的形式存在,不同线程操作同一对象时只会竞争同一object的同步代码块,即如果object不同的两个代码块可以同时执行。
synchronized 锁不同就异步 synchronized对static类是class锁,对非静态类是对象锁,所以对于同时synchronized标识的静态方法与非静态方法,执行异步。
重入锁:为了避免死锁,当线程获取一个对象锁,该线程可以再次获取该对象锁。synchronized就是重入锁。例如在一个synchronized声明的同步代码块中可以调用其他的同步代码块,而不会死锁。原理,每个锁关联一个计数器和占有它的线程,当计数器为0代表锁未被占用,当线程占有锁计数器置为1,当再次占用计数器依次递增。当线退出同步代码块时,计数器递减,直至为0,释放锁。
volatile 线程同步轻量级的实现,性能比synchronized好,但只能修饰变量不能修饰方法。
通知和等待机制 wait/notify机制
wait方法使当前正在执行的线程进入等待状态,将当前线程放入预执行队列,并且在wait所在的代码行停止执行,直到被通知或被中断,在继续从中断的位置开始继续执行,而不是从头执行。wait只能在同步代码块中调用。执行wait后当前锁会释放掉。
notify方法也只能在同步代码块中调用,当有多个线程等待,会由线程调试器随机挑选一个wait状态的线程发出通知。执行notify后要等到所在synchronized代码块执行完,才会通知到wait。object.notify随即唤醒一个,object.notifyAll()唤醒object对象锁所有处于wait状态的。
wait(long)和sleep(long)很相似,但是wait释放对象锁,sleep不释放对象锁。
public class demo2 { public static void main(String[] args) { Object object = new Object(); DemoThread demoThread = new DemoThread(object); new Thread(demoThread).start(); Demo1Thread demo1Thread = new Demo1Thread(object); new Thread(demo1Thread).start(); } } class DemoThread implements Runnable{ private Object object; public DemoThread(Object object){ this.object = object; } @Override public void run() { synchronized(object){ System.out.println("wait开始"); try { object.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("wait结束"); } } } class Demo1Thread implements Runnable{ private Object object; public Demo1Thread(Object object){ this.object = object; } @Override public void run() { synchronized (object){ System.out.println("notify开始"); object.notify(); System.out.println("notify结束"); } } }