多线程

有序严谨的指令集称为程序。
进程:
程序的同时多运行称为进程
线程:
程序中不同的执行路经称为线程
程序的最小执行单位
多线程:
如果在一个进程中同时运行了多个线程,用来完成不同的工作,则称为”多线程”
多线程的好处:
充分利用cpu的资源 编程简单
简化编程模型 效率高
带来良好的用户体验 易于资源共享

**主线程

Thread类
Java提供了java.lang.Thread类支持多线程编程
主线程
main()方法即为主线程入口
产生其他子线程的线程
必须最后完成执行,因为它执行各种关闭动作
多个线程交替执行,不是真正的并行。
线程每次执行时长由分配的CPU时间片长度决定

在Java中创建线程的几种方式

继承Thread类创建线程

//继承Thread类创建线程
public class MyThread extends Thread{
	public void run(){
		for(int i=0;i<100;i++){
	System.out.println(Thread.currentThread().getName());
		}
	}
}
public static void main(String[] args) {
		MyThread mt = new MyThread();
//需使用start()方法启动线程,如果直接调用线程中run()方法会:
		//1.只有主线程一条执行路径2.依次调用了两次run()方法
		mt.start();}

实现Runnable接口创建线程

//实现Runnable接口创建线程
public class MyRunnable implements Runnable {

	@Override
	public void run() {
		for(int i=0;i<100;i++){
			System.out.println(Thread.currentThread().getName());
		}
	}
public static void main(String[] args) {
	
		//创建线程对象
		MyRunnable mr = new MyRunnable();
		Thread t = new Thread(mr);
		t.start();
	}

实现Callable接口创建Thread线程

public class MyThread implements Callable<Integer> {
	
	@Override
	public Integer call() throws Exception {
System.out.println("子线程:"+Thread.currentThread().getName());
		return null;
	}
}
public class Test {
	public static void main(String[] args) {
		FutureTask<Integer> ft = new FutureTask<Integer>(new MyThread());
		Thread t = new Thread(ft,"01");
		System.out.println("主线程:"+Thread.currentThread().getName());
		t.start();
	}
}

线程状态:

创建状态
就绪状态
阻塞状态
运行状态
死亡状态

线程调度方法:

setPriority(int newPriority);更改线程的优先级
线程优先级由1~10表示,1最低,默认优先级为5
优先级高的线程获得CPU资源的概率较大
MAX_PRIORITY:静态常量 表示最大优先级
MIN_PRIORITY:静态常量 表示最小优先级

sleep(long millis);在指定毫秒数内让当前正在执行的线程休眠
让线程暂时睡眠指定时长,线程进入阻塞状态
睡眠时间过后线程会再进入运行状态
millis为休眠时长,已毫秒为单位
调用sleep()方法需处理InterruptedException异常
join(); 等待该线程终止
Join(long millis);
Join(long millis,int nanos);
使当前线程暂停执行,等待其他线程结束后在继续执行本线程
Millis:已毫秒为单位 的等待时长
Nanos:要等待的附加纳秒时长
需处理InterruptedException异常
yield(); 暂停当前正在执行的线程对象,并执行其他线程
暂停当前线程,允许其他具有相同优先级的线程获运行机会
该线程处于就绪状态,不转为阻塞状态
只是提供一种可能,但是不能保证一定会实现礼让
interrupt(); 中断线程
isAlive();测试线程是否处于活动状态

线程的同步:

线程不同步会遇到的问题:
当多个线程共享同一资源时,一个线程未完成全部操作的时候,其他线程会修改数据,造成数据不安全问题。

线程同步:
一段程序在执行过程中无论成功还是失败,其他线程都会等待这段程序执行完毕,才会转入其它线程。
这样可以保证程序的完整性和安全性。
同步方法
使用synchronized修饰的方法控制对类成员变量的访问
访问修饰符 synchronized 返回类型 方法名(参数列表){……}

同步方法:
//模拟网站
public class Site implements Runnable{
	//车票总数
	private int count = 10;
	//当前抢到第几张票
	private int num = 0;
	//表示车票是否卖完
	private boolean falg = false;
	
	@Override
	public void run() {

		while(!falg){
			sale();
		}
		
	}
	
	//同步方法实现售票
	public synchronized void sale(){
		if(count <= 0){
			falg = true;
			return;
		}
		//修改数据 (剩余车票总数,抢到第几张票)
		count--;
		num++;
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		//显示信息,反馈用户抢到第几张票
		System.out.println(Thread.currentThread().getName()+"抢到第"+num+"张票,剩余"+count+"张票。");
		
	}
	
}
//模拟多人抢票
public class SiteTest {
	public static void main(String[] args) {
		Site site = new Site();
		Thread t1 = new Thread(site,"小明");
		Thread t2 = new Thread(site,"小红");
		Thread t3 = new Thread(site,"小绿");
		
		t1.start();
		t2.start();
		t3.start();
	}
}

或者
synchronized 访问修饰符 返回类型 方法名(参数列表){……}

同步代码块:
public void run() {

		while(true){
			//同步代码块
			synchronized(this){
				if(count <= 0){
					return;
				}
				//修改数据 (剩余车票总数,抢到第几张票)
				count--;
				num++;
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				//显示信息,反馈用户抢到第几张票
				System.out.println(Thread.currentThread().getName()+"抢到第"+num+"张票,剩余"+count+"张票。");
			}
		}
		
	}

Synchronized()内为需同步的对象,通常为this
效果与同步方法相同
synchronized就是为当前的线程声明一把锁
多个并发线程访问同一资源的同步代码块时
同一时刻只能有一个线程进入synchronized(this)同步代码块
当一个线程访问一个synchronized(this)同步代码块时,其他synchronized(this)同步代码块同样被锁定
当一个线程访问一个synchronized(this)同步代码块时,其他线程可以访问该资源的非synchronized(this)同步代码

线程安全的类型:
ArrayList的add()方法定义
ArrayList类的add()方法为非同步方法
当多个线程向同一个ArrayList对象添加数据时,可能出现数据不一致问题

线程安全与非线程安全区别:
线程安全方法同步
效率较低
适合多线程多线程并发共享资源

非线程安全方法不同步
效率较高
适合单线程开发
常见类型对比
Hashtable 与 HashMap
Hashtable
继承关系
实现了Map接口,Hashtable继承Dictionary类
线程安全,效率较低
键和值都不允许为null
HashMap
继承关系
实现了Map接口,继承AbstractMap类
非线程安全,效率较高
键和值都允许为null
StringBuffer 与 StringBuilder
前者线程安全,后者非线程安全

死锁:两个线程都在等待对方先完成,造成程序的停滞
死锁的条件:
两个或两个以上的线程在活动
某个线程拿到一个锁以后,还想拿第二个锁,造成锁的嵌套

线程池:

尽量保证任务数不要超过最大线程数+阻塞队列的长度
使用线程池的好处:
重用存在的线程,减少对对象创建,消亡的开销
有效控制最大并发数,提高系统资源使用率
定时执行,定期执行

线程池所在的包:
Java.util.concurrent
顶级接口Executor,真正的线程池接口时ExecutorService
Java.util.concurrent.Executors类提供创建线程池的方法

创建线程池的方法:

newCachedThreadPool();创建一个可缓存的线程池,有任务时才创建新任务

/**
 * 使用newCachedThreadPool()方法创建线程池
 * */
public class Test {
	public static void main(String[] args) {
		ExecutorService pool =	Executors.newCachedThreadPool();
		//在线程池中执行10个任务
		for (int i = 0; i < 10; i++) {
			pool.execute(new MyRunnable(i));
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	
	}
}

class MyRunnable implements Runnable{
	int num;
	
	public MyRunnable() {
		super();
	}
	
	public MyRunnable(int num) {
		this.num = num;
	}

	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName()+":"+num);
		
	}
}

newSingleThreadExecutor();创建一个单线程池

/**
 * 使用newSingleThreadPool()方法创建线程池
 * */
public class Test2 {
	public static void main(String[] args) {
		ExecutorService pool =	Executors.newSingleThreadExecutor();
		//在线程池中执行10个任务
		for (int i = 0; i < 10; i++) {
			pool.execute(new MyRunnable(i));
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	
	}
}



class MyRunnable implements Runnable{
	int num;
	
	public MyRunnable() {
		super();
	}
	
	public MyRunnable(int num) {
		this.num = num;
	}

	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName()+":"+num);
		
	}
}

newFixedThreadPool(int nThread)创建一个固定长度的线程池,空闲线程会一直保留。参数nThread设定线程池中线程的数目

/**
 * 使用newFixedThreadPool()方法创建线程池
 * */
public class Test {
	public static void main(String[] args) {
		ExecutorService pool =	Executors.newFixedThreadPool(3);
		//在线程池中执行10个任务
		for (int i = 0; i < 10; i++) {
			pool.execute(new MyRunnable(i));
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	
	}
}

class MyRunnable implements Runnable{
	int num;
	
	public MyRunnable() {
		super();
	}
	
	public MyRunnable(int num) {
		this.num = num;
	}

	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName()+":"+num);
		
	}
}

newScheduledThreadPool(int corePoolSize)创建一个固定长度的线程池,而且已延迟或定时的方式来执行任务

/**
 * 使用newScheduledThreadPool()方法创建线程池
 * */
public class Test {
		public static void main(String[] args) {
			ScheduledExecutorService service= Executors.newScheduledThreadPool(3);
			service.scheduleAtFixedRate(new MyRunnable(), 1, 2, TimeUnit.SECONDS);
			
		}
}

class MyRunnable implements Runnable{

	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName()+"延时5秒执行,每2秒执行一次");
		
	}
}

ThreadPoolExecutor类构造器各个参数的含义:

**corePoolSize:核心池的大小
maximumPoolSize:线程池最大线程数
KeepAliveTime:表示线程没有任务执行时最多保持多久时间会中止
unit:参数KeepAliveTime的时间单位
workQueue:一个阻塞队列,用来存储等待执行的任务
threadFactory:线程工厂,主要用来创建工厂
Handler:表示当拒绝处理任务时的策略**

自定义线程池:

/**
 * 
 * 创建自定义线程池
 * 
 * */
public class Test {
	public static void main(String[] args) {
		//创建自定义线程池   尽量保证:任务数不要超过最大线程数+阻塞队列的长度
		ThreadPoolExecutor executor = new ThreadPoolExecutor(5,7,300,TimeUnit.MINUTES,new ArrayBlockingQueue<Runnable>(4));
		
		for(int i=0;i<12;i++){
			executor.execute(new MyRunnable(i));
			System.out.println("线程池中线程数:"+executor.getPoolSize()+",对列中等待任务执行数:"+executor.getQueue().size()+",已经执行完的任务数:"+executor.getCompletedTaskCount());
		}
		executor.shutdown();
	}
}


class MyRunnable implements Runnable{
	int num;//第几个任务
	 
	public MyRunnable(int num) {
		super();
		this.num = num;
	}
	@Override
	public void run() {
	   System.out.println("正在执行任务"+num);
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		System.out.println("任务"+num+"执行完毕");
	}
	
	
}

后台线程的特点:

随着前台线程的运行而运行
随着前台线程的消亡而消亡

SetDaemon():将线程设置为后台线程 GC 传入为true是将线程设置为后台线程,默认false
isDaemon():判断是否是后台线程

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值