java 多线程
10
Java线程状态
NEW ---状态是指刚创建 , 尚未启动。
RUNNABLE --- 状态是正在正常中 , 当然可会有某时 /IO待的操作 /CPU时片切换 ,这个状态下发生的等待, 不是 , Sleep。
BLOCKED ---这个 个状态下 , 是在多个有同步操作的场景 , 比如正在待另一个的 synchronized 块的执放
WAITING --- 个状态下是指拥有了某个之后 , 用了他的 wait方法, 待其他 /拥有用 notify / notifyAll
TIMED_WAITING --- 个状态就是有的 (时制 )的WAITING, 一出现在用 wait(long), join(long)情况下 ,
另外一个 sleep后, 也会入 TIMED_WAITING状态
TERMINATED --- 个状态下 的 run方法已执完毕了 , 基本上就于死亡了。
线程的状态
首先新建一个线程,然后启动,启动后变成runnable状态,表示已经准备就绪可以执行了,或者正在执行当中。执行完了后终止。
blocked:访问临界区,如果拿不到临界区的资源,需要等待。被动的等待。
waiting:主动发起的等待。自己的数据没准备好。
timedwaiting:限时等待。跟waiting相似。这个有时间限制,比如设置5秒钟。不管5秒内数据有没有准备好,都执行。waiting是不限时间的等待。
线程的基本操作
Thread t1 = new Thread(){ //新建线程 @Override public void run(){ System.out.println("hello"); } }; t1.start(); //启动线程,run方法被执行
Thread t1 = new Thread(); t1.run();//在当前线程中执行。不是另外开启的线程。要想异步,必须start
不用重载run方法。使用Runable接口实现。
public class testRunable implements Runnable{ public static void main(String[] args) { Thread t1 = new Thread(new testRunable()); //传入参数的模式。一般推荐 t1.start(); } @Override public void run() { System.out.println("OK"); } }
终止线程
Thread.stop();//不推荐使用。他会释放所有的monitor。有可能一个类中其他赋值还没有完成就停止了。这样就造成数据不同步,把对象写坏。会释放锁
中断线程,写一个支持中断的线程,可以有效的控制数据不被写坏。
t1.interrupt();//中断线程 Thread.currentThread().isInterrupted(); ///判断是否被中断 Thread.currentThread().interrupted();//判断是否被中断,并清除当前中断状态。
sleep 线程睡眠。释放cpu。抛出异常后,会清除中断标记位,所以需要在抛出异常的时候,再次中断。
public void run() { // TODO Auto-generated method stub while(true){ if(Thread.currentThread().isInterrupted()){ //线程被中断 退出 break; } try { Thread.sleep(20000); //如果睡眠被中断,就会醒来 } catch(InterruptedException e){ //抛出异常后,会清除中断标记位 System.out.println("interrupted when sleep"); Thread.currentThread().interrupt(); //设置中断 这样 当再次回到while循环的时候,就能判别有没有被中断。 } Thread.yield(); } } }
挂起 suspend和 继续执行resume。这两个方法都是被废弃的。
suspend不会释放锁
如果枷锁发生resume之前,会发生死锁。
等待线程结束 join和谦让yeild
public class JoinMain { public volatile static int i = 0; public static class AddThread extends Thread { @Override public void run() { for (i = 0; i < 1000000; i++); } } public static void main(String[] args) throws InterruptedException { AddThread at = new AddThread(); at.start(); at.join(); //主线程停止执行,等待线程执行完,再打印i的值 System.out.println(i); } }
join的本质
while (isAlive()){ //判断当前线程还活着,当线程执行完毕后,系统会调用 notifyAll() wait(0); //调用wait方法 }
//不要在Thread实例上使用wait() 和notify()方法 这样会干扰jdk内部实现。
synchronized 用来管理和控制临界区。
-给指定对象加锁:给指定对象加锁。进入同步代码前要获得给定对象的锁
-给实例方法加锁:相当于对实例加锁。进入同步代码前要获得当前实例的锁
-给静态放假加锁:相当于给当前类加锁。进入同步代码前要获得当前类的锁
public class SynchronizedTest extends Thread { public Object instance; public static int i; @Override public void run(){ for(int j=0;j<100000;j++){ //指定枷锁对象 一次只有一个线程 synchronized(instance){ i++; } } } //用在方法上 表示increase所在的对象上加锁 如果每次生成不同的实例,这个锁是没有用的 public synchronized void increase(){ i++; } // 表示给increase2 所在的类上加锁 。就算有不同的锁也可以锁住,因为类只有一个 public static synchronized void increase2(){ i++; } }
public class Accounting implements Runnable { static Accounting instance = new Accounting(); static int i=0; //锁加载Accounting类上 是可以锁住的 public synchronized static void increase(){ i++; }
// 锁加在instance实例上 也是可以锁住的 输出2000000 // public synchronized void increase(){ // i++; // }
@Override public void run() { for (int j=0;j<1000000;j++){ increase(); } } public static void main(String[] args) throws InterruptedException{ Thread t1 = new Thread(instance); Thread t2 = new Thread(instance); t1.start();t2.start(); t1.join(); t2.join(); System.out.println(i); //运行结果,输出2000000 } }
public class Accounting implements Runnable { static Accounting instance = new Accounting(); static int i=0; //锁加在instance实例上 public synchronized void increase(){ i++; } @Override public void run() { for (int j=0;j<1000000;j++){ increase(); } } public static void main(String[] args) throws InterruptedException{ Thread t1 = new Thread(new Accounting()); Thread t2 = new Thread(new Accounting()); t1.start();t2.start(); t1.join(); t2.join(); System.out.println(i); //因为初始化了不同的实例 所以是锁不住的 需要把increase 改成static } }
Object.wait() 让线程等待。一般是数据没有准备好,所以等待
Object.notify() 通知在这个对象上等待的线程,可以继续工作了。不用再等待了。 如果有多个等待的线程,会随机先通知一个。
public class wnTest { public Object object = new Object(); public class wn2 extends Thread { public void run(){ synchronized(object){ System.out.println(System.currentTimeMillis()+" :wn2 start!notify one thread"); object.notify(); System.out.println(System.currentTimeMillis()+" :wn2 end!"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class wn1 extends Thread { public void run(){ synchronized(object){ System.out.println(System.currentTimeMillis()+" :wn1 start!"); try { System.out.println(System.currentTimeMillis()+" :wn1 wait for object"); object.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(System.currentTimeMillis()+" :wn1 end!"); } } } public void ext(){ wn1 w = new wn1(); wn2 w2 = new wn2(); w.start(); w2.start(); } public static void main(String[] args) { new wnTest().ext(); } }
//执行结果 1498404259216 :wn1 start! 1498404259216 :wn1 wait for object 1498404259216 :wn2 start!notify one thread 1498404259216 :wn2 end! 1498404261221 :wn1 end! //因为有个sleep操作,wn2不能马上执行完,导致wn1不能马上拿到锁。所以有时间差
线程安全
当多个线程对同一arraylist进行添加时,可能一个线程获取到的arraylist size为5 而另一个线程获取arrayList的size为3,当给arralist继续添加的时候,就会增加到第四个。但第四个已经被线程一添加过了。所以会抛出异常,而且获取的总是是小于预期的。
public class ArrayListMultiThread { static ArrayList<Integer> al = new ArrayList<Integer>(10); public static class AddThread implements Runnable{ @Override public void run() { for (int i=0;i<1000;i++){ al.add(i); } } } public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new AddThread()); Thread t2 = new Thread(new AddThread()); t1.start();t2.start(); t1.join(); t2.join(); System.out.println(al.size()); //抛出异常 返回小于2000的数值。 } }
包装为线程安全的
import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Vector; import java.util.concurrent.CopyOnWriteArrayList; public class safeArrayList { //将list变为线程安全的方法 对于所有的集合都是通用的 static List<Integer> al = Collections.synchronizedList(new LinkedList<Integer>()); public static List<String> l = Collections.synchronizedList(new LinkedList<String>()); public static List<String> l2 = new Vector(); public static List<String> l3=new CopyOnWriteArrayList<String>(); public static class AddThread implements Runnable{ @Override public void run() { for (int i=0;i<1000;i++){ al.add(i); } } } public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new AddThread()); Thread t2 = new Thread(new AddThread()); t1.start();t2.start(); t1.join(); t2.join(); System.out.println(al.size()); //2000 } }
public static Map m= Collections.synchronizedMap(new HashMap()); public static Map m2 = new ConcurrentHashMap();
ConcurrentHashMap的性能高于Collections.synchronizedMap。因为ConcurrentHashMap不是锁整个hashmap。而是把hashmap继续分成16个segments,每一个segments都是一个hashmap,每一次对它操作的时候,不需要锁整个对象,当有一个对象进来后,先锁整个对象,再查落在哪一个segments,然后锁单个segments就行。提高哦并发度。所以推荐。