基本概念
- 通过Thread的实例来创建新的线程,
- 每个线程都是铜鼓某个特定的Thread对象所对应的方法run()来完成操作,方法run()称线程体。
- 通过调用Thread累的
start()
方法启动一个线程。
创建和启动
- 第一种:定义线程类实现Runnable接口,
Thread myThread = new Thread (target)//target为Runnable接口类型
,Runnable中只用一个方法,public void run()
,推荐使用这种。 - 第二种:可以定义Thread子类,重写run方法 :
calss MyThread extends Thead{ public void run(){} }
,然后生成该类对象:MyThread myThread = new MyThread()
控制方法
isAlive()//判断是否还活着
getPriority()//获得线程的优先级数值
setPriority()//设置现成的优先级数值
sleep()//将当前线程睡眠指定毫秒数,打断睡眠时抛出异常
interrupt()//打断
join()//调用某线程该方法,使该线程结束再恢复当前线程运行,可传参数,代表该线程先运行参数的毫秒时间再一块运行。传0等于不传
yield()//让出一会cpu,当前线程进入就绪队列
安全中断线程的一个实例,用标志中断,尽量不用interrupt和stop
public class TestThread {
public static void main(String[] args) {
Runner r = new Runner();
Thread t = new Thread(r);
t.start();
r.shutDown();
}
}
class Runner implements Runnable{
private boolean flag = true;
public void run() {
int i = 0;
while(flag==true) {
System.out.println(" "+ i++);
}
}
public void shutDown() {
flag = false;
}
}
线程同步
synchronized(){...}
public synchronized void add(){...}//互斥锁
- 加了synchronized的代码一次只有一个线程能访问
- 加了synchronized的两个函数一次只有一个能执行
死锁
多个线程需要锁定多个资源,互不相让。
生产者消费者问题
多个生产者和多个消费者中一次只有一个能进行生产或消费
public class ProducerConsumer {
public static void main(String[] args) {
MyStack ms = new MyStack();
Producer p = new Producer(ms);
Consumer c = new Consumer(ms);
new Thread(p).start();
new Thread(p).start();
new Thread(c).start();
new Thread(c).start();
}
}
class Mo{
int id;
Mo(int id){
this.id=id;
}
public String toString() {
return "Mo :"+id;
}
}
class MyStack{
int index = 0;
Mo[] arrMo = new Mo[6];
public synchronized void push(Mo m) {
while(index == arrMo.length) {
try {
this.wait();//执行wait()方法时,会释放当前的锁,进入等待,
} catch(InterruptedException e){
e.printStackTrace();
}
}
this.notify();//notify()/notifyAll()唤醒一个或多个正处于等待的线程,但不会立即释放锁
arrMo[index] = m;
index++;
}
public synchronized Mo pop() {
while(index == 0) {
try {
this.wait();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
this.notify();
index--;
return arrMo[index];
}
}
class Producer implements Runnable{
MyStack ms = null;
Producer(MyStack ms){
this.ms = ms;
}
public void run() {
for(int i=0;i<20;i++) {
Mo m = new Mo(i);
ms.push(m);
System.out.println("生产: "+m);
try {
Thread.sleep((int)(Math.random()*1000)
);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable{
MyStack ms = null;
Consumer(MyStack ms){
this.ms = ms;
}
public void run() {
for(int i = 0; i< 20;i++) {
Mo m = ms.pop();
System.out.println("消费: "+m);
try {
Thread.sleep((int)(Math.random()*1000));
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
要注意的点
- wait()、notify/notify()方法时Object的本地final方法,必须要在synchronized代码块中执行,说明当前线程一定是获取了锁的。
- 当前线程执行wait()方法时,会释放当前的锁,然后让出CPU,进入等待状态。只有当notify/notifyAll被执行时,会唤醒一个或多个正处于等待的线程
- notify/notifyAll()的执行只是唤醒沉睡的线程,而不会立即释放锁。
- 在进行条件判断时,使用while而不是if,会更安全。
wait()和sleep()的区别
wait()是Object类的方法
sleep()是Thread类的方法
wait()和sleep()都能将线程等待一段时间,但是wati()方法会释放当前的锁而sleep()不会。