一、基础知识
1、synchronized关键字
synchronized关键字最主要有以下3种应用方式,下面分别介绍:
- 修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁
- 修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁
- 修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。
2、常用的方法
- setName:设置线程名称,使之与参数name相同;
- getName:返回该线程的名称;
- start:使该线程开始执行,Java虚拟机底层调用该线程的start0( )方法;
- run:调用线程对象run方法。start底层会创建新的线程,run是一个简单的方法调用,不会启动新线程。
- setPriority:更改线程的优先级;
- getPriority:获取线程的优先级;
- sleep:在指定的毫秒数内让当前正在执行的线程休眠;
- interrupt:中断线程,但并没有真正结束线程,所以一般用于中断正在休眠线程。
- yield:线程的礼让。
- join:线程的插队
3、线程实现的方法
(1)继承Thread类创建线程
Thread类本质上是实现了Runnable接口的一个实例,代表一个线程的实例。启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("This is a thread.");
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
}
(2)实现Runable接口创建线程
如果自己的类已经extends另一个类,就无法直接extends Thread,此时,可以实现一个Runnable接口
public class MyThread1 implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
MyThread1 myThread1 = new MyThread1();
Thread thread = new Thread(myThread1);
thread.start();
}
}
二、代码实现
/**
* 线程通信的应用:经典例题:生产者/消费者问题
*
* 生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品,
* 店员一次只能持有固定数量的产品(比如:20),如果生产者试图生产更多的产品,
* 店员会叫生产者停一下,如果店中有空位放产品了再通知生产者继续生产;
* 如果店中没有产品了,店员会告诉消费者等一下,
* 如果店中有产品了再通知消费者来取走产品。
*
* 分析:
* 1.是否是多线程的问题?是,生产者的线程,消费者的线程
* 2.是否有共享数据的问题?是,店员、产品、产品数
* 3.如何解决线程的安全问题?同步机制,有三种方法
* 4.是否涉及线程的通信?是
*/
public class Clerk {
private int productCount=0;
// 生产产品
public synchronized void produceProduct(){
if (productCount <20) {
productCount++;
System.out.println(Thread.currentThread().getName()+":开始生产第"+productCount+"个产品");
notify();
}else {
// 等待
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// 消费产品
public synchronized void consumeProduct(){
if (productCount >0) {
System.out.println(Thread.currentThread().getName()+":开始消费第"+productCount+"个产品");
productCount--;
notify();
}else {
// 等待
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//消费者
public class Consumer extends Thread{
private Clerk clerk;
public Consumer(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
System.out.println(getName()+":开始消费产品......");
while (true){
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.consumeProduct();
}
}
}
//生产者
public class Producer extends Thread{
private Clerk clerk;
public Producer(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
System.out.println(getName()+":开始生产产品......");
while(true){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.produceProduct();
}
}
}
public class ProductTest {
public static void main(String[] args) {
Clerk clerk=new Clerk();
Producer p1=new Producer(clerk);
p1.setName("生产者1");
Consumer c1=new Consumer(clerk);
c1.setName("消费者1");
Consumer c2=new Consumer(clerk);
c2.setName("消费者2");
p1.start();
c1.start();
c2.start();
}
}