基本概念
- 进程与线程:举个例子,电脑上运行的各个应用程序为进程,那么在一个应用程序中的运行的为线程。执行的程序为进程,一个进可以产生多个线程。
- 多线程:同时多条线程同时运行,就好像你个人可以边吃饭边听歌一样。
实现多线程的两种方法
两种方法
- 用extends继承Thread类
- 用implements实现Runnable接口
方法一`
public class TestThread extends Thread {
//重写run方法
public void run() {
for(int i=0;i<10;i++) {
System.out.println("输出:"+i);
}
}
public static void main(String[] args) {
TestThread thread=new TestThread();
thread.start();
}
}
方法二
public class TestThread2 implements Runnable{
public void run() {
for(int i=0;i<10;i++) {
System.out.println("2号输出"+i);
}
}
public static void main(String[] args) {//将实现了Runnable类的对象作为参数传入
Thread thread = new Thread(new TestThread2());
thread.start();
}
}
画重点:实现Runnable时将这个实现类的对象作为参数传入到新建的线程对象在,从而可以调用实现类中的方法。
获得线程的基本信息获取
- 线程的命名,setname()
- 得到线程的名字,getname()
- 判断线程是否“活着”,isAlive()
- 取得线程本身的方法,currentThread()
- 设置线程优先级,setPriority(),1-10级,级数越高,运行可能高,并不是一定先运行
public class TestThread3 extends Thread{
public void run() {
for(int i = 0;i<5;i++) {//取正在运行的线程,并得到他的名字
System.out.println(Thread.currentThread().getName()+"输出"+i);
}
}
public static void main(String[] args) {
TestThread3 thread1=new TestThread3();
thread1.setName("线程1");
TestThread3 thread2=new TestThread3();
thread2.setName("线程2");
System.out.println("thread1的名字为"+thread1.getName());
System.out.println("判断thread2是否还存在"+thread2.isAlive());
thread1.setPriority(10);
thread1.start();
thread2.start();
}
}
终止线程的方法
思路:设置一个条件,while判断,条件满足时,可以运行run方法里的方法体,条件不满足时,则不运行
public class TestThread4 implements Runnable{
boolean a=true;
public void run() {
int i=0;
System.out.println("ok");
while(a) {
System.out.println("线程在运行"+(i++));
}
System.out.println("线程结束");
}
public void cease() {
a=false;
}
public static void main(String[] args) {
TestThread4 ttt=new TestThread4();
Thread thread=new Thread(ttt);
thread.start();
for(int i=0;i<20;i++) {
System.out.println("主线程运行"+i);
}
ttt.cease();
System.out.println("线程该停了");
}
}
线程联合
两个线程同时运行,相互嵌合,当其中一个运行完成之后另外一个才能继续运行。
方法:线程.join()
public class TestThread5 {
public static void main(String[] args) {
A thread1=new A();
thread1.start();
try {
thread1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("A接过了B买的东西");//-------------------②
}
}
class A extends Thread{
public void run() {
System.out.println("A让B去买东西");
B thread2=new B();
thread2.start();
try {
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("B买好了");//----------①
}
}
class B extends Thread{
public void run() {
System.out.println("B买东西要四分钟");
for(int i=0;i<4;i++) {
System.out.println("已经过了"+i+"分钟");
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行后会发现,输出语句①定要thread2运行完后才会运行,输出语句②要thread1运行完后才会运行
线程同步
同步方法:synchronized()
public class TestSync {
public static void main(String[] args) {
Account a1=new Account(100,"高");
Drawing draw1=new Drawing(80,a1);
Drawing draw2=new Drawing(80,a1);
draw1.start();
draw2.start();
}
}
class Account {
int money;
String name;
public Account(int money,String name) {
this.name=name;
this.money=money;
}
}
class Drawing extends Thread{
int drawingNum;//取多少钱
Account account;
int total;//取钱总数
public Drawing(int drawingNum,Account account) {
this.account=account;
this.drawingNum=drawingNum;
}
public void run() {
if(account.money-drawingNum<0) {
System.out.println(this.getName()+"取款,余额不足,取款失败!!!");
return;
}
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.money-=drawingNum;
total+=drawingNum;
System.out.println(this.getName()+"账户余额"+account.money);
System.out.println(this.getName()+"共取了"+total);
}
}
当两个线程同时使用一个空间是,会发生问题,就如上面,thread0和thread1同时在只有100的银行里取钱,却取出来总和160的钱,解决这个问题的方法是在关键部分使用synchronized()方法,在synchronized块里面只能有一个线程进去。
public void run() {
synchronized(account) {
if(account.money-drawingNum<0) {
System.out.println(this.getName()+"取款,余额不足,取款失败!!!");
return;
}
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.money-=drawingNum;
total+=drawingNum;
System.out.println(this.getName()+"账户余额"+account.money);
System.out.println(this.getName()+"共取了"+total);
}
}
生产者——消费者模型
- 方法:wait();notify();
一个是等待,一个是通知,当线程运行到wait是,只有接收到一个notify的通知时才能继续运行,在线程并发协作时,需要用到这两个方法。 - 生产者——消费者模型,设计三个类:
生产者类:生产数据;
消费者类:取出数据;
存储类:存储数据;
给一个最大的存储量和初始数据量,通过生产者、消费者的生产、取出变换存储数据量,数据达到最大值时,生产者wait,知道得到消费者通知notify()已经消费时,继续生产,反之亦然。
public class Wait_notify {
public static void main(String[] args) {
Bank bank =new Bank();
//生产者线程
produce thread0=new produce(bank);
produce thread1=new produce(bank);
produce thread2=new produce(bank);
//消费者线程
consumer thread3=new consumer(bank);
consumer thread4=new consumer(bank);
consumer thread5=new consumer(bank);
thread0.start();
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread5.start();
}
}
class Bank {
private int total=6;
private int max =10;
public synchronized void remove () {
//可消费
if(total>0) {
total--;
System.out.println(Thread.currentThread().getName()+"消费一件资源,此时为"
+total+"件" );
this.notifyAll();
}else {
//等待增加
try {
System.out.println("已经没有库存,等待生产者增加");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void add() {
//数量小于最大值,增加
if(total<max) {
total++;
System.out.println(Thread.currentThread().getName()+"生产一件资源,此时为"
+total+"件" );
this.notifyAll();
}else {
//数量已满,等待消费
try {
System.out.println("数量已满,等待消费者消费");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class produce extends Thread {
private Bank bank;
produce(Bank bank) {
this.bank=bank;
}
public void run() {
while(true) {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
bank.add();
}
}
}
class consumer extends Thread{
private Bank bank;
consumer(Bank bank) {
this.bank=bank;
}
public void run() {
while(true) {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
bank.remove();
}
}
}