zoukankan      html  css  js  c++  java
  • 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就行。提高哦并发度。所以推荐。
  • 相关阅读:
    背包九讲——动态规划
    Collection、Map、数组 遍历方式
    TCP三次握手与四次挥手
    数据结构——B树、B+树
    数据结构——红黑树
    数据结构——二叉查找树、AVL树
    jquery 抽奖示例
    comebotree树
    初玩Linux部署项目
    springMvc + websocket 实现点对点 聊天通信功能
  • 原文地址:https://www.cnblogs.com/milanmi/p/7078054.html
Copyright © 2011-2022 走看看