多线程(二)

<small>

线程安全

当多线程对共享资源同时曹组时,可能会发生数据的脏读、乱读现象,最终导致数据紊乱,是在多线程编程时必须要避免的问题。

实现线程同步操作

同步:要求多线程依次执行,当第一个线程在操作共享资源(执行一段代码),其他线程处于等待状态,到第一个线程处理完毕,其他线程中,获得CPU分配时间的那一个则可以操作共享资源(执行代码)
异步:多线程互相操作,互不干扰。
synchronize:同步操作
关键词的操作有三种方式:
1、作用在普通方法上
表示同一时间,只能有一个线程在执行该方法,等到此线程执行结束,获得CPU分配时间的那一个则可以操作共享资源(执行代码)

public class ThreadDemo01 {

    public static void main(String[] args) {
        final Table table = new Table();
        //电脑1的桌子
        Thread thread1 = new Thread(){
            @Override
            public void run() {
                while(true){
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //欢乐斗地主
                    String name = 
                        Thread.currentThread().getName();
                    System.out.println(name+" 玩了一局欢乐豆,还剩:"+table.playGame());
                }
            }
        };
        //电脑2的桌子
        Thread thread2 = new Thread(){
            @Override
            public void run() {
                while(true){
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //欢乐斗地主
                    String name = 
                        Thread.currentThread().getName();
                    System.out.println(name+" 玩了一局欢乐豆,还剩:"+table.playGame());
                }
            }
        };

        thread1.start();
        thread2.start();
        
    }

}
class Table{
    int beans = 1000;//系统第一次赠送1000个欢乐豆
    
    public synchronized int playGame(){
        if(beans <= 0){
            //玩完了,game over。
            throw new RuntimeException("欢乐豆不足,请充值...");
        }
        return beans -= 100;//每玩一局,系统扣除100欢乐豆
    }
}

2、作用在代码块上(最常用)
如果仅对代码块实现同步效果,目的就是提高代码的多线程操作,缩小需要同步的范围,目的就是提高代码的运行效率
实现语法:
synchronize(共享的对象){
需要同步的代码块
}

共享对象: this , 静态OBject全局变量

public class ThreadDemo02 {
public static void main(String[] args) {
        final Shop youYiKu = new Shop();
        //客户1
        Thread customer1 = new Thread(){
            @Override
            public void run() {
                youYiKu.shopping(Thread.currentThread().getName());
            }
        };
        //客户2
        Thread customer2 = new Thread(){
            @Override
            public void run() {
                youYiKu.shopping(Thread.currentThread().getName());
            }
        };

        customer1.start();
        customer2.start();  
}
}
 * 模拟客户进店挑选、试衣、结账离开效果。
class Shop{
    public /*synchronized*/ void shopping(String peopleName){
        try {
            System.out.println(peopleName+"进店了....");
            System.out.println(peopleName+"正在挑选衣服...");
            Thread.sleep(5000);
            /*
             * 此优衣库只有一个试衣间
             */
            synchronized(this){
                System.out.println(peopleName+"挑选完毕,正在试衣...");
                Thread.sleep(5000);
            }
            System.out.println(peopleName+"试衣完毕,结账离开。");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

3、作用在静态方法上(不常用)
多线程共享操作的数据,属于类的,与对象无关,无论多少个对象,数据只有一份,多线程对静态数据操作,也可能会发生数据脏读、乱读现象,所以可以对静态方法实现同步。
结论:
同步(加锁)范围,适当就好
多线程的使用就是为了提高代码执行效率
不恰当的对代码、方法惊醒加锁,反而降低了代码的执行效率,不可取
所以同步范围决定着多线程代码的执行效率

线程中的五中状态
新建 new,待执行runnable,执行running,阻塞blocking,死亡dead

Object 中的其他方法

wait,notify,notifyAll
当需要某个进程后台执行,不影响主线程时,可以考虑用以下程序

模拟垃圾百度全家桶

public class ObjectMethodDemo04 extends Object{
public static void main(String[] args) {
        final Object obj = new Object();
        /*
         * 搜狗输入法下载线程
         */
        final Thread souGouDownLoad = new Thread(){
            @Override
            public void run() {
                System.out.println("搜狗输入法下载 start...");
                for(int i=1; i<=100; i++){
                    System.out.println("下载了 "+i+"%");
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("搜狗输入法下载 end...");
                
                /*
                 * 要求搜狗输入法,在下载完毕时,就安装
                 * 百度安全认证的下载安装,是后台执行或者是
                 * 在搜狗输入法安装之后才执行。
                 */
                //要对共享的Object obj对象实现wait的线程唤醒操作
                synchronized(obj){
//                  obj.notify();//唤醒被当前Object对象阻塞的线程。
                    obj.notifyAll();//唤醒被当前Object对阻塞的所有的线程。
                }
                
                /*
                 * 百度安全认证流氓下载、安装。
                 */
                System.out.println("百度安全认证下载 start...");
                for(int i=1; i<=100; i++){
                    System.out.println("下载了 "+i+"%");
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("百度安全认证下载 end...");
                
                System.out.println("百度安全认证安装 start...");
                for(int i=1; i<=100; i++){
                    System.out.println("安装了 "+i+"%");
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("百度安全认证安装 end...");
            }
        };
        
        /*
         * 搜狗输入法安装线程
         */
        Thread souGouFixed = new Thread(){
            @Override
            public void run() {
                System.out.println("搜狗输入法安装 start...");
                
                try {
                    synchronized(obj){
                        //先下载,才能安装
                        souGouDownLoad.start();
                                              souGouDownLoad.join();
                                              obj.wait();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
                for(int i=1; i<=100; i++){
                    System.out.println("安装了 "+i+"%");
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("搜狗输入法安装 end...");
            }
        };
        
        souGouFixed.start();
                
    }

线程池

  • 利用有效的线程数量,处理更多的任务。
  • 有效的控制了内存的不必要消耗,提高服务器的性能。
  • 线程池:限制线程数量的。
  •       有规律的处理更多的任务。
    
public class ThreadPoolDemo05 {
public static void main(String[] args) {
        ExecutorService threadPool = 
                Executors.newFixedThreadPool(2);
        Runnable runnable = null;
        for(int i=0; i<5; i++){
            final int number = i+1;
            runnable = new Runnable(){
                @Override
                public void run() {
                    try {
                        System.out.println(Thread.currentThread().getName()+
                                            "在执行任务"+number);
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }; 
       Thread thread = new Thread(runnable);
* 将任务交给线程池来管理,
 *   线程池会分配不同的线程去执行任务。
 */
            threadPool.execute(runnable);
        }
        
        //将线程池关闭
        threadPool.shutdown();
        
    }
}

将不安全的集合线程转换为安全的集合线程

public class SynchronizedCollectionDemo05 {

    public static void main(String[] args) {
        /*
         * 线程非安全的List
         *      → 线程安全的List集合 
         * 
         * 通过Colleactions工具类中的集合同步方法
         */
        List list = new ArrayList();
        //非安全的list → 线程安全的list
        list = Collections.synchronizedList(list);
        
        /*
         * 线程非安全的Set
         *      → 线程安全的Set集合 
         * 
         * 通过Colleactions工具类中的集合同步方法
         */
        Set set = new HashSet();
        //非安全的set → 线程安全的set
        set = Collections.synchronizedSet(set);
        
        /*
         * 线程非安全的Map
         *      → 线程安全的Map集合 
         * 
         * 通过Colleactions工具类中的集合同步方法
         */
        Map map = new HashMap();
        //非安全的map → 线程安全的map
        map = Collections.synchronizedMap(map);

    }

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容