目录
- -线程的概念
- -创建线程的两种方式
- -线程的状态和生命周期
- -sleep()和join方法
- -线程的优先级
- -同步
- -线程间通信
什么是进程?
进程是一个运行的程序;
是指可执行程序并存放在计算机存储器的一个指令序列,它是一个动态执行的过程。
什么是线程?
线程是比进程还要小的运行单位,一个进程包含多个线程;
线程可以看做是一个子程序。
线程的创建
- 创建一个Thread类,或者一个Thread子类的对象
- 子类继承Thread类
- 在子类中重写run()方法
- 主方法main中调用start()方法启动线程
- 创建一个实现Runnable接口的类的对象
通过线程实现类创建对象
将实现类的对象创建Thread的对象2
将实现类的对象创建Thread的对象2
Thread类
Thread是一个线程类,位于java.lang包下
构造方法 | 说明 |
Thread() | 创建一个线程对象 |
Tread(String name) | 创建一个具有指定名称的线程对象 |
Thread(Runnable target) | 创建一个基于Runnable接口实现类的线程对象 |
Tread(Runnable target,String name) | 创建一个基于Runnable接口实现,并且指定名称的线程对象 |
Thread类的常用方法
方法 | 说明 |
public void run() | 线程相关的代码写在该方法中,一般需要重写 |
public void start() | 启动线程的方法 |
public static void sleep(long m) | 线程休眠m毫秒的方法 |
public void join() | 优先执行调用join()方法的线程 |
Runnable接口
- 只有一个run();方法
- Runnable是java中实现线程的接口
- 实现线程功能的类都必须实现该接口
1、线程的简单创建-继承Thread:
package com.demo.day9.thread;
/*
* 通过基础Thread类的方式创建线程类,重写run()方法
*/
class MyThread extends Thread{
public void run() {
System.out.println(getName()+"该线程正在执行!");
}
}
public class ThreadTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("主线程1");
MyThread mt=new MyThread();//创建对象
mt.start();//调用start()方法启动线程,执行run方法
//start();只能执行一次
System.out.println("主线程2");
}
}
线程使用CPU的使用权是随机的:
package com.demo.day9.thread;
class MyThreadOne extends Thread {
//构造方法,给线程取个名字
public MyThreadOne(String name) {
super(name);
}
public void run() {
for(int i=1;i<10;i++) {
System.out.println(getName()+"正在运行"+i+"次");
}
}
}
public class TreadOne {
public static void main(String[] args) {
//创建线程对象
MyThreadOne mt1=new MyThreadOne("线程1");
MyThreadOne mt2=new MyThreadOne("线程2");
mt1.start();
mt2.start();
//线程获取CPU的使用权是随机的、执行结果随机
}
}
输出结果随机。。
2、线程创建-实现Runnale接口创建线程
为什么要实现Runnable接口?
- java不支持多继承
- 不打算重写Thread类的其他方法
- java支持实现多接口
简单案例:
package com.demo.day9.thread;
/*
* 通过实现Runnable接口创建线程
*/
//创建线程实现类 PrintRunnale
class PrintRunnable implements Runnable{
@Override
public void run() {
//输出正在进行的线程
int i=1;
while(i<10)
System.out.println(Thread.currentThread().getName()+"正在进行"+(i++)+"次");
//Thread.currentThread().getName() 获取当前正在进行线程的名字
}
}
public class MyRunnable {
public static void main(String[] args) {
//通过线程实现类创建对象
PrintRunnable pt =new PrintRunnable();
//将实现类的对象创建Thread的对象2
Thread th=new Thread(pt);
th.start();
//将实现类的对象创建Thread的对象2
//两个对象共用一个实现类对象
Thread th2=new Thread(pt);
th2.start();
}
}
线程的状态和生命周期
线程的五个状态
- 新建(New)
- 可运行(Runnable)(又叫就绪)
- 正在运行状态(Running)
- 阻塞(Blocked)
- 终止(Dead)
线程的生命周期
sleep方法的应用
- Thread类的方法
public static void sleep(long millis)
- 作用:在指定的毫秒数内让正在执行的线程休眠,暂停执行
- 参数为休眠的时间,单位是毫秒
package com.demo.day9.thread;
//通过实现Runnable接口创建线程
class MyThreadTwo implements Runnable{
@Override
public void run() {
for(int i=1;i<15;i++) {
System.out.println(Thread.currentThread().getName()+"正在进行"+i+"次");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}//让线程休眠1秒
}
}
}
public class ThreadTwo {
public static void main(String[] args) {
// 创建线程类对象
MyThreadTwo mt=new MyThreadTwo();
//通过线程类对象创建Thread类对象调用start方法
Thread th=new Thread(mt);
th.start();
}
}
join方法的使用(强制CPU控制权)
- Thread类的方法
public final void join()
- 作用:等待调用该方法的线程结束后,之后的线程才能执行
public final void join(long millis)
作用:等待该线程终止的最长时间为millis毫秒,无论该线程是否执行完,要释放CPU控制权
线程的优先级
- java为线程类提供了10个优先级
- 优先级可以用整数1-10表示,超过范围会抛出异常
- 主线程默认优先级为5
- 优先级常量
- -MAX_PRIORITY:线程的最高优先级10
- -MIN_PROIRITY:线程的最低优先级1
- -NORM_PROIRITY:线程的默认优先级
- 优先级相关的方法
方法 | 说明 |
public int getPriority() | 获取线程的优先级的方法 |
public void setPriority() | 设置线程的优先级的方法 |
线程同步synchronized
多线程运行存在的问题
各个线程是通过竞争CPU时间而获得运行机会的
- 各线程什么时候得到CPU时间,占用多久,是不可预测的
- 一个正在运行着的线程在什么地方被暂停是不确定的
银行存取款案例:
Bank.java
package com.demo.day9.thread;
public class Bank {
private int balance;//账户余额
private String account;//账户
//带参构造,为变量赋值
public Bank(String account,int balance) {
this.setAccount(account);
this.setBalance(balance);
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
//重写toString
public String toString() {
return "账户为:"+this.getAccount()+" "+"余额为:"+this.getBalance();
}
//存钱的方法
public void savaAccount(){
synchronized (this){//同步,执行这个线程,不允许其他线程抢占CPU
int balance=getBalance();//获取当前账户余额
try {
Thread.sleep(1000);//让线程休眠1秒
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
balance+=100;//存入100元
setBalance(balance);//
System.out.println("存款后账户余额:"+balance);
}
}
public void drawAccouct() {
int balance=getBalance();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
balance-=200;//取款200
setBalance(balance);
System.out.println("取款后账户余额:"+balance);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
SaveAccount.java
package com.demo.day9.thread;
/*
* 存款
*/
//通过实现Runnable接口来创建线程
public class SaveAccount implements Runnable{
Bank bank;//创建Bank对象
public SaveAccount(Bank bank) {
super();
this.bank = bank;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
@Override
public void run() {
// TODO Auto-generated method stub
bank.savaAccount();
}
}
DrawAccount.java
package com.demo.day9.thread;
/*
* 取款
*/
public class DrawAccount implements Runnable {
Bank bank;
public DrawAccount(Bank bank) {
super();
this.bank = bank;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
@Override
public void run() {
// TODO Auto-generated method stub
bank.drawAccouct();
}
}
Test.java
package com.demo.day9.thread;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Bank bank=new Bank("1001",1000);//创建对象bank
SaveAccount sa=new SaveAccount(bank);
DrawAccount da=new DrawAccount(bank);
//创建线程对象
Thread save =new Thread(sa);
Thread draw =new Thread(da);
save.run();
draw.run();
try {
draw.join();
save.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(bank);
}
}
输出:
存款后账户余额:1100
取款后账户余额:900
账户为:1001 余额为:900
银行存取款问题
- 为了保证在存款或取款的时候,不允许其他线程进行操作
- 需要将Bank对象进行锁定
- 使用关键字synchronized实现
同步
synchronized关键字用在
成员方法
public synchronized void saveAccount(){}
静态方法
public static synchronized void saveAccount(){}
语句块
synchronize (obj){.....}
线程间通信
- wait()方法:中断方法的执行,是线程等待
- 如果不配合notify方法使用,可能使两个线程都处于等待状态,陷入死锁
- notify()方法:唤醒处于等待的某个线程,使其等待结束
- notifyAll()方法:唤醒所有处于等待的线程,使他们结束等待
案例要求:
- 生产者每生产一个后,消费者消费一个;
- 不能存在生产者生产一个,消费者消费两个
- 或者生产者生产两个,消费者消费一个
Queue.java
package com.demo.day9.thread;
public class Queue {
private int n;
boolean flag=false;//设默认flag为false。默认先生产
public synchronized int getN() {
if(!flag) {//执行等待
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("消费"+n);
flag=false;//消费完毕,再flag重新赋值为false
notifyAll();//与wait()搭配使用,唤醒所有线程
return n;
}
public synchronized void setN(int n) {
if(flag) {//如果容器里有数据,flag为true,执行等待
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("生产"+n);
this.n = n;
flag=true;//生产完毕,重新另flag为true
notifyAll();//唤醒所有的线程
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
Producer.java
package com.demo.day9.thread;
public class Producer implements Runnable{
Queue queue;
Producer( Queue queue){
this.setQueue(queue);
}
public Queue getQueue() {
return queue;
}
public void setQueue(Queue queue) {
this.queue = queue;
}
@Override
public void run() {
// TODO Auto-generated method stub
int i=0;
while(true) {
queue.setN(i++);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Consumer.java
package com.demo.day9.thread;
public class Consumer implements Runnable {
Queue queue;
public Consumer(Queue queue) {
super();
this.queue = queue;
}
@Override
public void run() {
while(true)
{
queue.getN();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
TestQ.java
package com.demo.day9.thread;
public class TestQ {
public static void main(String[] args) {
// 创建Queue对象
Queue queue=new Queue();
//创建对象
Producer p1=new Producer(queue);
Consumer c1=new Consumer(queue);
//实现上面创建的对象
// Thread p=new Thread(p1);
// Thread c=new Thread(c1);
// p.start();
// c.start();
new Thread(new Producer(queue)).start();
new Thread(new Consumer(queue)).start();
}
}
输出结果:
生产0
消费0
生产1
消费1
生产2
消费2
生产3
消费3
生产4
消费4
生产5
消费5
生产6....
综合案例:
生成天气数据,然后显示出来
Weather.java
package com.test;
/*
* 这是一个天气类Weather,用于温度和湿度数据的存放和读取
*/
public class Weather {
private int temperature;//温度
private int humidity;//湿度
boolean flag=true;
//带参构造
Weather(){
this.setHumidity(humidity);
this.setTemperature(temperature);
}
//生成天气数据的方法
public synchronized void generateWeather(int temp,int hum) {
if(!flag)//如果flag=false
{
try {
wait();//如果为flag为假让它等待
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.setHumidity(hum);
this.setTemperature(temp);
System.out.println("生成天气数据:"+"[温度:"+this.getTemperature()+",湿度:"+this.getHumidity()+"]");
notifyAll();//唤醒所有等待
flag=false;//重新flag赋值为false
}
//显示天气数据的方法
public synchronized void readWeather() {
if(flag) {//如果为真等待
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("读取天气数据:"+"[温度:"+this.getTemperature()+",湿度:"+this.getHumidity()+"]");
notifyAll();//唤醒所有等待
flag=true;//重新flag赋值为false
}
public int getTemperature() {
return temperature;
}
public void setTemperature(int temperature) {
this.temperature = temperature;
}
public int getHumidity() {
return humidity;
}
public void setHumidity(int humidity) {
this.humidity = humidity;
}
}
GenerateWeather.java
package com.test;
/*
* 这个是个线程类,用于生成天气数据,模拟生成100次
*/
public class GenerateWeather implements Runnable{
Weather weather;
GenerateWeather(Weather weather){
this.weather=weather;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
@Override
public void run() {
int i=1;
int temp=32;
int hum=26;
while(i<100) {
temp+=1;
hum+=1;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
weather.generateWeather(temp,hum);
i++;
}
}
}
ReadWeather.java
package com.test;
/*
* 这是一个线程类,用于读取天气数据
*/
public class ReadWeather implements Runnable {
Weather weather;
ReadWeather(Weather weather){
this.weather=weather;
}
@Override
public void run() {
// TODO Auto-generated method stub
int i=1;
while(i<100) {
weather.readWeather();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
i++;
}
}
}
WeatherTest.java
package com.test;
public class WeatherTest {
public static void main(String[] args) {
Weather wt=new Weather();
new Thread(new GenerateWeather(wt)).start();
new Thread(new ReadWeather(wt)).start();
}
}
显示结果
生成天气数据:[温度:33,湿度:27]
读取天气数据:[温度:33,湿度:27]
生成天气数据:[温度:34,湿度:28]
读取天气数据:[温度:34,湿度:28]
生成天气数据:[温度:35,湿度:29]
读取天气数据:[温度:35,湿度:29]
生成天气数据:[温度:36,湿度:30]
读取天气数据:[温度:36,湿度:30]
生成天气数据:[温度:37,湿度:31]
读取天气数据:[温度:37,湿度:31]
生成天气数据:[温度:38,湿度:32]
读取天气数据:[温度:38,湿度:32]
.......