阿猛学习笔记java十二多线程

十七多线程

1.进程

正在运行的程序,有自己的地址空间

资源分配的基本单位

进程特点:动态性,并发性,独立性

2.线程

进程内部的一个执行单元,是程序的单一控制流程

线程特点:线程是独立调度和分派的基本单位,共享进程资源

​ 减少程序在并发执行时付出的时间和空间开销

多线程优点:进程间不能共享内存,但线程之间可共享内存

​ 使用多线程实现多任务并发比进程的效率高

​ 多线程使系统空转时间减少,提高CPU的利用率

​ java语言内置多线程功能支持,简化了Java的多线程编程

3.Thread
常用属性

static int MAX_PRIORITY 线程最高优先级 10

static int MAX_PRIORITY 线程最低优先级 1

static int NORM_PRIORITY 线程默认优先级 5

构造方法

Thread(Runnable target)

Thread(String name)

Thread(Runnable target,String name)

1.继承Thread,重写run方法

常用方法

static ThreadcurrentThread() 得到当前线程

long getId() 返回线程的id

String getName() 返回线程的名称

void setName(Striing name) 修改线程的名称

int getPriority() 返回线程的优先级

void setPriority() 修改线程的优先级

Thread.State getState() 返回线程的状态

ThreadGroup getThreadGroup() 返回线程所属的线程组

void interrupt() 中断线程

static boolean interrupted() 线程是否中断

boolean isAlive() 线程是否活着

boolean isDaemon() 是否是守护线程

void join() 等待线程死亡

void join(long millis) 等待线程死亡,最多millis毫秒

static void sleep(long millis) 线程以指定的毫秒数暂停

void start() 线程开始执行调用run方法(线程启动方法)

void run() 调用Runnable的run方法

String toString() 线程的字符串表示,包括名称,优先级和线程组

static void yield() 对调度程序的暗示,表示当前线程愿意产生当前使用的处理器

void destory() 销毁线程

4.创建线程
继承Thread,重写run()方法
public class S1Thread extends Thread{
	String name;
	public S1Thread(String name) {
		this.name = name;
	}
	@Override
	public void run() {
		for(int i=3;i>0;i--){
			System.out.println(Thread.currentThread()+"\t剩余"+(i-1)+"张票");
		}
	}
	public static void main(String[] args) {
		S1Thread thread1=new S1Thread("线程1");
		S1Thread thread2=new S1Thread("线程2");
		System.out.println("线程最高优先级:"+thread1.MAX_PRIORITY);
		System.out.println("线程最低优先级:"+thread1.MIN_PRIORITY);
		System.out.println("线程默认优先级:"+thread1.NORM_PRIORITY);
		System.out.println("线程id:"+thread1.getId());
		System.out.println("线程name:"+thread1.getName());
		System.out.println("线程优先级:"+thread1.getPriority());
		System.out.println("线程状态:"+thread1.getState());
		System.out.println("线程所属组"+thread1.getThreadGroup());
		System.out.println("线程是否中断:"+thread1.interrupted());
		System.out.println("线程是否活着:"+thread1.isAlive());
		System.out.println("线程是否是守护线程:"+thread1.isDaemon());
		thread1.start();
		thread2.start();
	}
}
线程最高优先级:10
线程最低优先级:1
线程默认优先级:5
线程id:11
线程name:Thread-0
线程优先级:5
线程状态:NEW
线程所属组java.lang.ThreadGroup[name=main,maxpri=10]
线程是否中断:false
线程是否活着:false
线程是否是守护线程:false
Thread[Thread-1,5,main]	剩余2张票
Thread[Thread-0,5,main]	剩余2张票
Thread[Thread-0,5,main]	剩余1张票
Thread[Thread-1,5,main]	剩余1张票
Thread[Thread-0,5,main]	剩余0张票
Thread[Thread-1,5,main]	剩余0张票
实现Runnable,实现run方法
public class S2Runnable implements	 Runnable{
	int i=6;
	public void run() {	
		for(;i>0;i--){
			System. out .println(Thread. currentThread ()+"剩余"+(i-1)+"张票");
			}
	}
	public static void main(String[] args) {
		System.out.println("实现Runnable创建线程,多个线程共享一个Thread对象,线程共享全局资源");
		S2Runnable thread=new S2Runnable();
		//两个线程共享资源
		Thread thread1=new Thread(thread);
		Thread thread2=new Thread(thread);
		thread1.setPriority(4);
		thread1.start();
		thread2.start();
	}
}

实现Runnable创建线程,多个线程共享一个Thread对象,线程共享全局资源
Thread[Thread-0,4,main]剩余5张票
Thread[Thread-1,5,main]剩余5张票
Thread[Thread-0,4,main]剩余4张票
Thread[Thread-1,5,main]剩余3张票
Thread[Thread-0,4,main]剩余2张票
Thread[Thread-1,5,main]剩余1张票
Thread[Thread-0,4,main]剩余0张票

两种线程创建方式比较:

两种线程创建方式的比较
继承 Thread 类方式的多线程
优势:编写简单
劣势:无法继承其它父类
实现 Runnable 接口方式的多线程
优势:可以继承其它类,多线程可共享同一个 Thread 对象的全局资源
劣势:编程方式稍微复杂,如果需要访问当前线程,需要调用

5.线程状态

新生:使用new关键字创建线程后,尚未调用其start方法之前

可运行:调用线程对象start方法之后(可能在运行,也可能等待运行)

阻塞:一种不可运行状态,在得到一个特定事件后会返回可运行状态

死亡:线程的run方法运行完毕或运行中出现未捕获的异常

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0SZ7J39j-1603264351405)(C:\Users\lgm\AppData\Roaming\Typora\typora-user-images\1603247776417.png)]

6.线程调度

每个线程都有(默认是5)的优先级,线程调度会优先考虑级别高的线程

默认情况下,一个线程继承其父类线程的优先级

优先级影响线程的切换

当线程显示放弃,睡眠、阻塞或自愿放弃控制权时,所有线程都接受检查且优先级高的会优先执行

优先级高的线程可抢占优先级低线程的资源

同级别的线程,通过控制权的释放,确保所有线程均有机会运行

线程调度的常用方法:

setPriority(int p) 改变线程优先级

join() 阻塞指定线程等另一个线程完成后在继续执行

sleep() 进入被阻塞状态,经过指定时间后自动转为可运行状态

​ 没有其他等待执行的线程,如果没有经过指定时间,该线程也程不会马上恢复执行,反之则会马上恢复 执行

yield() 让当前正在执行的线程暂停,将线程转入可运行状态

​ 没有其他等待执行的线程,这个时候当前线程就会 马上恢复执行

setDaemon 将指定线程设置为后台线程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5N9TBMD4-1603264351409)(C:\Users\lgm\AppData\Roaming\Typora\typora-user-images\1603251297432.png)]

//测试yield()
class ThreadYield1 extends Thread {
	public ThreadYield1(String name){
		super(name);//调用父类的构造方法初始化name
	}
	public void run() {
		for (int i = 0; i < 3; i++) {
				System.out .println(Thread.currentThread().getName()+ (i + 1) + "次运行");
				Thread.currentThread().yield ();//礼让			
	}
	}
}
class ThreadYield2 extends Thread {
	public ThreadYield2(String name){
		super(name);//调用父类的构造方法初始化name
	}
	public void run() {
		for (int i = 0; i < 3; i++) {
			System.out .println(Thread.currentThread().getName()+ (i + 1) + "次运行");
			Thread.currentThread().yield ();
	}
	}
}
//测试daemon()
class ThreadDaemon extends	Thread{
	public ThreadDaemon(String name){
		super(name);//调用父类的构造方法初始化name
	}
	public void run() {
		while ( true) {
			System.out .println(Thread.currentThread().getName());
		}
		}
}
public class S3ThreadControl extends Thread{
	public S3ThreadControl(String name){
		super(name);//调用父类的构造方法初始化name	
	}
	@Override
	public void run() {
		for(int i=0;i<3;i++){		
			System.out.println(Thread.currentThread().getName()+" "+i);
		}
	}
	public static void main(String[] args) throws InterruptedException {
		for(int i=0;i<5;i++){
			if(i==3){
				S3ThreadControl threadControl=new S3ThreadControl("半路加入的线程");	
				threadControl.start();
				threadControl.sleep(2000);//线程等待2s后再执行
				threadControl.join();//阻塞线程等另一个线程完成后在继续执行
			}
			System.out.println(Thread.currentThread().getName()+" "+i);
		}
		ThreadYield1 threadYield1=new ThreadYield1("yield1线程");
		ThreadYield2 threadYield2=new ThreadYield2("yield2线程");
		threadYield1.start();
		threadYield2.start();
		ThreadDaemon threadDaemon=new ThreadDaemon("后台线程");		
		threadDaemon.setDaemon(true);//设置为后台线程
		threadDaemon.join();
		for(int i=0;i<3;i++){
			System.out.println(Thread.currentThread().getName()+" "+i+"判断是否是后台进程:"+threadDaemon.isDaemon());//判断是否是后台进程
			threadDaemon.interrupt();//中断线程
		}
	}
}

main 0
main 1
main 2
半路加入的线程 0
半路加入的线程 
半路加入的线程 2
main 3
main 4
yield1线程1次运行
yield1线程2次运行
yield2线程1次运行
yield1线程3次运行
yield2线程2次运行
yield2线程3次运行
main 0判断是否是后台进程:true
main 1判断是否是后台进程:true
main 2判断是否是后台进程:true
7.线程同步

当多个线程访问一个数据时,确保资源在某一时刻只被一个线程使用,保证数据安全

同步代码块实现

synchronized(obj){

​ 同步代码块

}

同步方法实现

访问修饰符 synchronized 返回类型 方法名{

​ 同步代码块

}

class Account {
	int balance = 800;// 余额	
	public void withdraw(int amount) {// 取款
		balance = balance - amount;
	}
}
public class S4synchronizedCodeBlock implements Runnable{
	Account acct=new Account();	
	public void run() {
		for(int x=0;x<5;x++){		
		try {
				makeWithdrawal(100,x);//取款
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}	
	}
	//同步代码块实现
	/*private	void makeWithdrawal(int amt,int x) throws InterruptedException{
		synchronized(acct){
			if(acct.balance>amt){
				System.out.println("取款\t"+Thread.currentThread().getName()+",余额为"+"\t"+acct.balance);				
				acct.withdraw(amt);//如果余额足够,则取款
			}else{
				System.out.println(Thread.currentThread().getName()+"取款余额不足,余额为"+"\t"+acct.balance);
			}
		}
	}*/
	//同步方法实现
	private	 synchronized void makeWithdrawal(int amt,int x) throws InterruptedException{
			if(acct.balance>amt){
				System.out.println("取款\t"+Thread.currentThread().getName()+",余额为"+"\t"+acct.balance);				
				acct.withdraw(amt);//如果余额足够,则取款
			}else{
				System.out.println(Thread.currentThread().getName()+"取款余额不足,余额为"+"\t"+acct.balance);
			}
	}
	public static void main(String[] args) {
		// 创建两个线程分别表示张三和张三的老婆
		S4synchronizedCodeBlock r = new S4synchronizedCodeBlock();
		Thread one = new Thread(r);
		Thread two = new Thread(r);
		one.setName("张三");
		two.setName("张三的妻子");
		one.start();
		two.start();
		
	}
}

取款	张三,余额为	800
取款	张三,余额为	700
取款	张三,余额为	600
取款	张三的妻子,余额为	500
取款	张三的妻子,余额为	400
取款	张三的妻子,余额为	300
取款	张三的妻子,余额为	200
张三的妻子取款余额不足,余额为	100
张三取款余额不足,余额为	100
张三取款余额不足,余额为	100
8.死锁

当两个或两个以上的线程相互等待对方释放资源的现象

出现死锁后,不会出现异常和提示,只是所有的线程都处于阻塞状态

线程同步的优点:解决了线程安全问题

线程同步的缺点:性能下降

​ 会出现死锁

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值