多线程知识回顾

1、多线程基础知识

  多线程之间抢占资源,会存在大量的保护现场(包括执行的变量数据等等资源)和恢复现场(恢复刚才执行到那一步了)。所以也会比较慢。

  什么是NIO和BIO呢?Nginx就是NIO,当大量请求过来时,nginx会开启线程来接受请求,但Http请求是BIO,需求请求等待逐个执行了。

2、进程的概念:

  进程是申请资源的最小单位,所有的线程共享进程的资源,一个进程最少会有一个线程,多的就是无数了。

3、多线程咋说:

  如果电脑是一核一个CPU,那么同时只能执行一个进程的一个线程。现在是超线程技术。一个cpu执行两个线程。四核八线程。就是四个CPU可以执行八个线程。

4、多线程的创建:

  

 

 

 5、创建线程的问题: 使用thread和runnable的区别。一个是创建一个对象,一个是创建多个对象。

/**
 * 此时出现的问题:
 *      1、每次在启动线程对象的时候都会创建自己对象的属性值,相当于每个线程操作自己,没有真正意义上实现贡献
 *          解决方法:将共享对象,共享变量设置成static
 *      2、每次访问共享对象的时候,数据不一致了、
 *          解决方法:使用线程同步
 *
 *
 */
public class TicketThread extends Thread{

    private static int ticket = 5;

    @Override
    public void run() {
        for(int i = 0;i<100;i++){
            if (ticket > 0) {
                System.out.println(Thread.currentThread().getName() + "正在出售第" + (ticket--) + "张票");
            }
        }
    }

    public static void main(String[] args) {
        TicketThread t1 = new TicketThread();
        TicketThread t2 = new TicketThread();
        TicketThread t3 = new TicketThread();
        TicketThread t4 = new TicketThread();
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}
 1 /**
 2  * 使用接口的方式,每次只创建了一个共享对象,所有的线程能够实现资源共享
 3  *      1、数据不一致的问题
 4  *          解决方法:线程同步
 5  *
 6  */
 7 public class TicketRunnable implements Runnable {
 8 
 9     private int ticket = 5;
10 
11     @Override
12     public void run() {
13         for (int i = 0; i < 100; i++) {
14             if (ticket > 0) {
15                 System.out.println(Thread.currentThread().getName() + "正在出售第" + (ticket--) + "张票");
16             }
17         }
18     }
19 
20     public static void main(String[] args) {
21         TicketRunnable ticket = new TicketRunnable();
22         Thread t1 = new Thread(ticket);
23         Thread t2 = new Thread(ticket);
24         Thread t3 = new Thread(ticket);
25         Thread t4 = new Thread(ticket);
26 
27         t1.start();
28         t2.start();
29         t3.start();
30         t4.start();
31     }
32 }

6、多线程之间的代理模式设计: 来自/设计模式之禅

第 2 章 代理模式【Proxy Pattern】
什么是代理模式呢?我很忙,忙的没空理你,那你要找我呢就先找我的代理人吧,那代理人总要知道
被代理人能做哪些事情不能做哪些事情吧,那就是两个人具备同一个接口,代理人虽然不能干活,但是被
代理的人能干活呀。 
比如西门庆找潘金莲,那潘金莲不好意思答复呀,咋办,找那个王婆做代理,表现在程序上时这样的: 
先定义一种类型的女人: 
package com.cbf4life.proxy; 
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 定义一种类型的女人,王婆和潘金莲都属于这个类型的女人
*/
public interface KindWomen { 
 
//这种类型的女人能做什么事情呢?
public void makeEyesWithMan(); //抛媚眼
 
 
public void happyWithMan(); //happy what? You know that!
 
} 
一种类型嘛,那肯定是接口,然后定义潘金莲: 
package com.cbf4life.proxy; 
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 定一个潘金莲是什么样的人
*/
public class PanJinLian implements KindWomen { 
public void happyWithMan() { 
 System.out.println("潘金莲在和男人做那个....."); 
 } 
第    8    页
您的设计模式
public void makeEyesWithMan() { 
 System.out.println("潘金莲抛媚眼"); 
 } 
} 
再定一个丑陋的王婆: 
package com.cbf4life.proxy; 
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 王婆这个人老聪明了,她太老了,是个男人都看不上,
* 但是她有智慧有经验呀,她作为一类女人的代理!
*/
public class WangPo implements KindWomen { 
private KindWomen kindWomen; 
 
public WangPo(){ //默认的话,是潘金莲的代理
 this.kindWomen = new PanJinLian(); 
 } 
 
//她可以是KindWomen的任何一个女人的代理,只要你是这一类型
public WangPo(KindWomen kindWomen){ 
 this.kindWomen = kindWomen; 
 } 
 
public void happyWithMan() { 
 this.kindWomen.happyWithMan(); //自己老了,干不了,可以让年轻的代替
 } 
public void makeEyesWithMan() { 
 this.kindWomen.makeEyesWithMan(); //王婆这么大年龄了,谁看她抛媚眼?!
 } 
} 
两个女主角都上场了,男主角也该出现了: 
第    9    页
您的设计模式
package com.cbf4life.proxy; 
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 定义一个西门庆,这人色中饿鬼
*/
public class XiMenQing { 
 
/*
 * 水浒里是这样写的:西门庆被潘金莲用竹竿敲了一下难道,痴迷了,
 * 被王婆看到了, 就开始撮合两人好事,王婆作为潘金莲的代理人
 * 收了不少好处费,那我们假设一下:
 * 如果没有王婆在中间牵线,这两个不要脸的能成吗?难说的很!
 */
public static void main(String[] args) { 
 //把王婆叫出来
 WangPo wangPo = new WangPo(); 
 
 //然后西门庆就说,我要和潘金莲happy,然后王婆就安排了西门庆丢筷子的那出戏:
 wangPo.makeEyesWithMan(); //看到没,虽然表面上时王婆在做,实际上爽的是潘金莲
 wangPo.happyWithMan(); } 
} 
那这就是活生生的一个例子,通过代理人实现了某种目的,如果真去掉王婆这个中间环节,直接是西
门庆和潘金莲勾搭,估计很难成就武松杀嫂事件。 
那我们再考虑一下,水浒里还有没有这类型的女人?有,卢俊义的老婆贾氏(就是和那个固管家苟合
的那个),这名字起的:“假使”,那我们也让王婆做她的代理: 
把贾氏素描出来: 
package com.cbf4life.proxy; 
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
*/
public class JiaShi implements KindWomen { 
public void happyWithMan() { 
 System.out.println("贾氏正在Happy中......"); 
第    10    页
您的设计模式
 } 
public void makeEyesWithMan() { 
 System.out.println("贾氏抛媚眼"); 
 } 
} 
西门庆勾贾氏: 
package com.cbf4life.proxy; 
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 定义一个西门庆,这人色中饿鬼
*/
public class XiMenQing { 
 
public static void main(String[] args) { 
 //改编一下历史,贾氏被西门庆勾走:
 JiaShi jiaShi = new JiaShi(); 
 WangPo wangPo = new WangPo(jiaShi); //让王婆作为贾氏的代理人
 
 wangPo.makeEyesWithMan(); 
 wangPo.happyWithMan(); 
 } 
} 
说完这个故事,那额总结一下,代理模式主要使用了 Java 的多态,干活的是被代理类,代理类主要是
接活,你让我干活,好,我交给幕后的类去干,你满意就成,那怎么知道被代理类能不能干呢?同根就成,
大家知根知底,你能做啥,我能做啥都清楚的很,同一个接口呗。

7、线程的状态: 进入线程阻塞状态有两种情况: 1、sleep 2、io阻塞。3、join方法。会阻塞当前的运行的线程,让别的线程运行。

        进入死亡情况有三种情况:1、正常执行完成  2、人为中断,使用stop方法  3、程序抛出未捕获的异常

 

 

 

 8、线程常见api

   join方法:让出当前运行的线程,让别的线程执行。调用该方法的线程强制执行。阻塞状态

   sleep():静态方法,让当前运行的线程睡眠多少毫秒,让别的线程来执行。阻塞状态

    yield()当前正在执行的线程暂停一次,允许其他线程执 行,不阻塞,线程进入就绪状态。可以再次进行资源的同时抢占 就绪状态

   stop() 强迫线程停止执行。已过时。不推荐使用。

9、线程安全数据同步问题:

  就是加锁  

  还有轻量级的CAS compare and swit

  synchronized 同步代码块,参数为当前对象。也就是当前的Thread对象。睡眠可以切换不同对象的资源抢占。

 

注意:
* 在多线程的时候,可以实现唤醒和等待的过程,但是唤醒和等待操作的对应不是thread类
* 而是我们设置的共享对象或者共享变量
* 多线程并发访问的时候回出现数据安全问题:
* 解决方式:
* 1、同步代码块
* synchronized(共享资源、共享对象,需要是object的子类){具体执行的代码块}
* 2、同步方法
* 将核心的代码逻辑定义成一个方法,使用synchronized关键字进行修饰,此时不需要指定共享对象
*
public class TicketRunnable2 implements Runnable {

    private int ticket = 5;

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (this){
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + "正在出售第" + (ticket--) + "张票");
                }
            }
        }
    }

    public static void main(String[] args) {
        TicketRunnable2 ticket = new TicketRunnable2();
        Thread t1 = new Thread(ticket,"A");
        Thread t2 = new Thread(ticket,"B");
        Thread t3 = new Thread(ticket,"C");
        Thread t4 = new Thread(ticket,"D");

        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

10、同步方法的实现

 

 11、生产和消费者的问题

  可以用wait和notify 现在用的是 java.util.concurrent 下的阻塞队列。

 12、线程池创建任务的过程:第三点是所有的线程,并非第一点的核心线程数。

 

 13、线程池的分类:

  

 

   第二个是延迟执行线程池。

 1 ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
 2         System.out.println(System.currentTimeMillis());
 3         scheduledExecutorService.schedule(new Runnable() {
 4             @Override
 5             public void run() {
 6                 System.out.println("延迟三秒执行");
 7                 System.out.println(System.currentTimeMillis());
 8             }
 9         },3, TimeUnit.SECONDS);
10         scheduledExecutorService.shutdown();

  延迟执行,每三秒执行一次

  ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
        System.out.println(System.currentTimeMillis());
        scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("1------延迟一秒执行,每三秒执行一次");
                System.out.println(System.currentTimeMillis());
            }
        },1,3, TimeUnit.SECONDS);

创建带有返回结果的线程两种方式:

FutureTask

复制代码
1 @SuppressWarnings("all")
2     public static void main(String[] args) throws ExecutionException, InterruptedException {
3         FutureTask futureTask = new FutureTask(new MyCallable());
4         Thread thread = new Thread(futureTask);
5         thread.start();
6         if(!futureTask.isDone())
7             System.out.println("task has not finished!");
8         System.out.println(futureTask.get());
9     }
复制代码

  

  线程池

复制代码
1 @SuppressWarnings("all")
2     public static void main(String[] args) throws ExecutionException, InterruptedException {
3         ExecutorService executorService = Executors.newCachedThreadPool();
4         Future future = executorService.submit(new MyCallable());
5         if(!future.isDone())
6             System.out.println("task has not finished!");
7         System.out.println(future.get());
8     }
posted @ 2022-04-04 20:48  Jerry&Ming  阅读(152)  评论(0)    收藏  举报