Java多线程机制

进程:程序的一次动态加载过程,包括了代码加载,编译,执行,结束的一个完整过程
线程:线程是比进程更小的单位,行为很像进程,一个进程在执行过程中可以产生多个线程
关系

多线程序机制:每个java程序都有一个主线程,当jvm加载代码,发现main方法,此时就会启动主线程,在mian方法执行过程中再创建的线程就是其他线程。

线程的四种状态:
新建状态:Thread类被创建
运行状态:执行run()方法
中断状态:

  • 1.资源从当前线程被切换给了其他线程
  • 2.调用sleep()方法
  • 3.wait()方法
  • 4 .线程执行某个操作期间进入了阻塞状态

死亡状态:1.正常运行完全部工作 2.被强制中断

状态图:
在这里插入图片描述
java线程的优先级在常数1-10之间,默认为5级

创建线程的三种方法:

1.线程任务类,接口Runnable

public class ThreadB implements Runnable{
	@Override
	public void run() {
		for(int i=0;i<10;i++) {
			System.out.println(i+"B线程");
		}
	}
}

启动线程时,需要通过Thread 对象进行启动

public class ThreadTestB {

	public static void main(String[] args) {
		//1.创建线程任务
		ThreadB tb=new ThreadB();
		//2.通过线程任务,创建线程对象
		Thread t=new Thread(tb);
		t.start();
		for(int i=0;i<10;i++) {
			System.out.println(i+"Main线程");
		}
	}

}

2.继承Thread的线程类

public class ThreadTestA {

	public static void main(String[] args) {
		//1.创建线程对象
		ThreadA ta=new ThreadA();
		ta.start();
		for(int i=0;i<10;i++) {
			System.out.println(i+"Main线程");
		}
	}

}

启动线程时,直接 new 线程对象.start()方法

public class ThreadA extends Thread{
	@Override
	public void run() {
		for(int i=0;i<10;i++) {
			System.out.println(i+"A线程");
		}
	}
}

线程同步(synchronized)

问题:当两个或多个线程同时访问同一变量时,并且对该变量会进行修改,那么就可能会出现混乱
线程同步方法:使用 synchronized 修饰来方法
线程同步机制:当一个线程A使用synchronized方法时,其他线程想用synchronized方法时就必须等待,直到线程A使用完synchronized方法。

例子:会计和出纳共同拥有一个账本,他们都可以使用saveOrTake方法对账本进行访问。如果会计正在使用saveOrTake存入钱时,出纳被禁止使用,反之如此。

package com.money;
//线程同步(synchronized):
public class Test {

	public static void main(String[] args) {
		Bank bank = new Bank();
		bank.setMoney(300);
		Thread accountant = new Thread(bank); //声明线程变量会计
		Thread cashier = new Thread(bank); //声明线程变量出纳
		accountant.setName("accountant");
		cashier.setName("cashier");
		accountant.start();
		cashier.start();
	}

}
package com.money;

public class Bank implements Runnable {
	int money = 200;
	public void setMoney(int n) {
		money = n;
	}
	
	public void run() {
		if(Thread.currentThread().getName().equals("accountant")) {
			saveOrTake(300);
		}else if(Thread.currentThread().getName().equals("cashier")) {
			saveOrTake(150);
		}
	}

	//存取方法  (如果将synchronized取掉,线程就不会有等待,结果将会不一样)
	public synchronized void saveOrTake(int amount) {
		if(Thread.currentThread().getName().equals("accountant")) {
			for(int i=1;i<=3;i++) {
				money=money+amount/3;   //每次存入100,暂停一下
				System.out.println(Thread.currentThread().getName()+
						"存入"+amount/3+"元,账上有"+money+"元");
			}
			try {
				Thread.sleep(1000);    //此时出纳无法使用saveOrTake方法
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		else if(Thread.currentThread().getName().equals("cashier")) {
			for(int i=1;i<=3;i++) {
				money=money-amount/3;   //每次取出50,暂停一下
				System.out.println(Thread.currentThread().getName()+
						"取出"+amount/3+"元,账上有"+money+"元");
			}
			try {
				Thread.sleep(1000);   //此时会计无法使用saveOrTake方法
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
	}
}

在这里插入图片描述


协调同步的线程(wait)

问题:当一个线程中在使用的同步方法时,需要用到其中的某个变量,而此变量又需要其他线程修改后才符合此线程的需要,此时就需要用wait()方法。
wait()方法:中断线程的执行,使当前线程等待,允许其他线程使用这个同步方法。使用完后通过线程结束等待:notify(),notifyall()

例子:A和B买电影票,电影票5元一张,售票员只有两张5元的钱,A有20元排第一位,B有5元排第二位。因此A必须等待B先买票。

package com.ticket;

public class Test {
	public static void main(String[] args) {
		Ticket ticket = new Ticket();
		Thread A = new Thread(ticket);
		Thread B = new Thread(ticket);
		A.setName("A");
		B.setName("B");
		A.start();
		B.start();
	}
}
package com.ticket;

public class Ticket implements Runnable {
	int five=2;
	int twenty=0;
	@Override
	public void run() {
		if(Thread.currentThread().getName().equals("A")) {
			saleTicket(20);
		}else if(Thread.currentThread().getName().equals("B")) {
			saleTicket(5);
		}
	}
	
	public synchronized void saleTicket(int money) {
		if(money==5) {
			five=five+1;
			System.out.println(Thread.currentThread().getName()+"拿到入场票");
		}else if(money==20) {
			while(five<3) {  //如果5元少于3张则需要等待
				try {
					System.out.println(Thread.currentThread().getName()+"等待买票");
					wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			five=five-3;
			twenty=twenty+1;
			System.out.println(Thread.currentThread().getName()+"拿到入场票,收到15元找零");
		}
		notifyAll();
	}
}

在这里插入图片描述


线程联合(join)

一个线程A在占有CPU期间可以让其他线程调用jion()和本线程联合
如B.join()。

如果在此期间联合了B线程,那么A线程会立即中断,执行B线程,直到B线程执行完毕,A线程再重新排队等待CPU资源,恢复执行。但是B线程是已经结束的线程,那么B.join()不会有效果。

join()和wait()有基本相同的效果。两者都是中断当前线程,让出CPU资源。原因在于join()底层的实现是基于wait(),不同处主要有:
1.wait()方法必须在synchronized方法中使用
2.wait()方法可以使用带毫秒参数的wait(long timeout)方法,在延迟timeout毫秒后,被暂停的线程将被恢复到锁标志等待池


守护线程

调用void setDaemon(boolean)将一个线程设置为守护线程,线程默认是非守护线程,非守护线程也称为用户线程
使用:thread.setDaemon(true);
效果:当所有用户线程都结束了,如果守护线程中run方法还没有执行完,守护线程也会立即结束

当线程A结束时,线程B虽然在while中,run方法中还未执行完毕,但是也会随着线程A一起结束

public class Test {

	public static void main(String[] args) {
		Daemon dam = new Daemon();
		Thread A = new Thread(dam);
		Thread B = new Thread(dam);
		A.setName("A");
		B.setName("B");
		A.start();
		B.setDaemon(true);  //线程B为守护线程
		B.start();
	}

}
public class Daemon implements Runnable {

	@Override
	public void run() {
		if(Thread.currentThread().getName().equals("A")) {
			for(int i=0;i<8;i++) {
				System.out.println("i="+i);
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}else if(Thread.currentThread().getName().equals("B")) {
			while(true) {
				System.out.println("线程B是守护线程");
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值