avatar

目录
Java线程类总结-创建、锁、安全机制

线程构造方法

  • 写一个实现类去继承Thread类并重写run方法

  • 写一个实现类去实现Runnable接口并重写run方法。

  • 使用匿名内部类去创建Thread t = new Thread(new Runnable{})但最终还是要用Thead方法去创建

  • 使用线程工厂ThreadFactory接口,新建实现类返回Thread对象,其实本质还是调用new Thread()方法

    java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class SimpleThreadFactory implements ThreadFactory {
    public Thread newThread(Runnable r) {
    return new Thread(r);
    }
    }
    // main方法
    public class Demo {
    public static void main(String[] args) {
    SimpleThreadFactory sF = new SimpleThreadFactory();
    sF.newThread(new Runnable() {
    @Override
    public void run() {
    System.out.println("线程创建成功");
    }
    }).start();

1.1 线程池的创建,使用Excutors类调用静态方法newFixedThreadPool(int capacity)

java
1
2
3
4
5
ExecutorService es = Executors.newFixedThreadPool(10);
// 提交一个线程任务
es.submit(new ThreadTest());
// ThreadTest类要实现Runnable接口
public class ThreadTest implements Runnable{}

线程安全机制

  • 利用Object类创建锁对象obj

    java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    public class Demo10MultiThread implements Runnable{
    // 定义总的票数
    private int ticket = 1000;
    // 定义锁对象
    Object obj = new Object();
    @Override
    public void run() {
    // 每个线程循环工作
    // 如果票数大于0
    // 如果为真
    // 正确写法
    while(true){
    synchronized (obj){
    // 这样的写法是错误的,如果想让多个线程同时共享资源,必须要sychronize修饰的代码块对应的程序运行一次
    //while(true){
    if(ticket>0){
    // 定义锁代码块,以免发生资源争抢
    try {
    Thread.sleep(5);
    // 票数减一
    ticket--;
    // 获取当前线程名称
    System.out.println(Thread.currentThread().getName()+"已为您取到了第"+ticket+"张票");
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }else{
    break;
    }
    }
    }
    }
  • 利用Lock类去创建lock对象

    java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    // 新建一个Lock对象,因为Lock是抽象类,所以要用子类去创建对象。
    ReentrantLock l = new ReentrantLock();
    // 复写父类run方法
    @Override
    public void run() {
    // 一个死循环
    while(true){
    // 获取到锁
    l.lock();
    try {
    if(ticket>1){
    // 定义锁代码块,以免发生资源争抢
    try {
    Thread.sleep(5);
    // 票数减一
    ticket--;
    // 获取当前线程名称
    System.out.println(Thread.currentThread().getName()+"已为您取到了第"+ticket+"张票");
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    } }finally {
    l.unlock();
    }
    }
    }
  • 注意无论创建几个线程都一定要保证锁对象是唯一的,才能解决线程安全问题

    java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 其实匿名内部类的方式,也是不可行的,因为每次都要创建一个obj锁对象,所以n个线程就会有n个锁对象。不合理。
    Demo10MultiThread run = new Demo10MultiThread();
    // 新建三个线程,分别启动
    Thread t1 = new Thread(run);
    Thread t2 = new Thread(run);
    Thread t3 = new Thread(run);
    t1.setName("Thread-0");
    t2.setName("Thread-1");
    t3.setName("Thread-2");
    t1.start();
    t2.start();
    t3.start();

生产者消费者问题(PV 操作)

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// 创建一个Obj对象的锁
Object obj = new Object();
// 其实使用Lock锁的效果是一样的。
Thread consumer = new Thread(new Runnable() {
@Override
public void run() {
// 循环吃包子
while (true) {
// 同步锁代码块
synchronized (obj){
// 老板快点做包子
System.out.println("顾客:老板来点包子");
// 模拟老板响应
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
// 包子铺老板线程
Thread banker = new Thread(new Runnable() {
@Override
public void run() {
while(true){
synchronized (obj){
System.out.println("老板:包子马上就好");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
// 通知来吃包子
System.out.println("老板:快来吃包子吧,包子好了啦");
System.out.println("--------------------");
obj.notify();
}
}
}
}
});

// 启动两个线程
consumer.start();
banker.start();
打赏
  • 微信
    微信
  • 支付宝
    支付宝