2021-04-14


一、进程与线程的定义

进程:一个应用程序的实例,当启动一个应用程序时,就创建该程序的实例,其实是开启了一个进程;然后就会分配内存,硬盘等电脑资源;
进程就是资源分配的基本单位。
线程:运行在进程之中,进程中可以开启线程;
一个进程中至少有一个线程,叫主线程,main方法就是该线程的入口;当然它也可以有多个线程,除了主线程外,其他的线程是由主线程中创建的。
线程是CPU调度的基本单位。

1.多线程的优点

(1).CPU的利用率比较高;
(2)用户的体验好;
(3)简化开发;

2.多线程的实现

第一步:创建线程,开启线程(java.lang.Thread)
实现有两种方法:
1.将类声明为Thread的子类。让该子类重写Thread类的run方法;
run()–线程体,具体描述线程的 执行任务;
start()–即让该线程开始执行;由Java虚拟机调用线程的run()方法。

package filecopy;

public class TestThread extends Thread{
	@Override
	public void run() {
		for(int i = 1;i<= 10;i++) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("i = " + i);
		}
	}
}
package filecopy;

public class Test {
	public static void main(String[] args) {
		Thread r = new TestThread();//调用子类对象
		r.start();
	}
}
	2.声明实现Runnable接口的类。该类实现run()方法;需要通过创建Thread来开启;
package filecopy;

public class TestThread implements Runnable{
	@Override
	public void run() {
		for(int i = 1;i<= 10;i++) {
			try {
				Thread.sleep(100);
				
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("i = " + i);
		}
	}
}
package filecopy;

public class Test {
	public static void main(String[] args) {
		Runnable n = new TestThread();
		Thread r = new Thread(n);
		r.start();
	}
}

*优缺点:*
1.前者通过继承,简单,但是继承有局限性;
2.后者通过接口实现run()方法,接口可以多实现,更加的灵活,可以实现资源的共享。

例如:实现多平台卖票

3.线程的状态

线程的调度:如何为多个线程分配CPU呢?
它是个复杂过程,受外界条件的干扰;
因素如下:
1.优先级:1-10之间的数字,默认值是5,值 越小,获取CPU的概率越高;
2.Thread.sleep(毫秒),休眠,调用该方法则线程进入休眠状态(阻塞),当休眠时间结束,线程继续运行;可能引发InterruptedException;使用场合:模拟任务消耗的时间;
3.join()加入,插队;
join(毫秒)即插队多少毫秒;其实例方法谁调用谁插队,等t线程执行完,其他线程才开始执行;也可能引发InterruptedException;
4.Thread.yield()礼让
其代码所在线程礼让,放弃本次抢占的时间片,重新进行下一次抢占,可能礼让成功,但也可能失败。(因为其放弃 本次抢占时间片,但其速率极快,在下一次抢占时,仍位于后面的代码,就会礼让失败)

4.多线程共享,引发的数据不一致问题

解决方法:
1.加锁–就是将读写作为一个整体,给其加锁;
(1)同步代码块:synchronized(对象锁)每个对象都有唯一的一把锁。
(2)同步方法:一个方法内部只有一个同步代码块,就写为同步方法,也就是将synchronized加在方法上,同步方法的锁都是this,即当前对象的锁;
区别:前者方法内可以出现多个同步代码块,并且同步代码块可以嵌套;后者一个线程访问同步方法时,其他的线程则都不能访问所有的同步方法,只能访问非同步的方法。相比之下,同步代码块更灵活,同步方法 可以改重用。(根据需求进行选用)
同步特点:
(1)线程安全(多线程访问下数据都是正确的);
(2)效率太低(不提倡将耗时的操作加入同步)
但是要注意:编码正确第一,效率第二;不能为了效率而忽略正确性的本质;
代码如下(示例):

package filecopy;

public class SellTicket implements Runnable{
	int tickets = 10;
	int num = 0;
	@Override
	public void run() {
		while(tickets>0) {
			synchronized(this) {
				if(tickets <= 0)return;
				tickets--;
				num++;
				try {
					Thread.sleep(50);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"卖出第"+num+"张票,剩余"+tickets+"张票");
			}
		}
	}
	ackage filecopy;

public class Test {
	public static void main(String[] args) {
		SellTicket r = new SellTicket();
		Thread t1 = new Thread(r,"窗口1");//多线程共同抢占资源;创建线程多个线程;
		Thread t2 = new Thread(r,"窗口2");
		Thread t3 = new Thread(r,"窗口3");
		t1.start();
		t2.start();
		t3.start();
	}
}
package filecopy;

public class SellTicket implements Runnable{
	int tickets = 10;
	int num = 0;
	@Override
	public void run() {
		while(tickets>0) {
//			synchronized(this) {
//				if(tickets <= 0)return;
//				tickets--;
//				num++;
//				try {
//					Thread.sleep(50);
//				} catch (InterruptedException e) {
//					e.printStackTrace();
//				}
//				System.out.println(Thread.currentThread().getName()+"卖出第"+num+"张票,剩余"+tickets+"张票");
//			}
			sell();
		}
	}
	public synchronized void sell() {
		if(tickets <= 0)return;
		tickets--;
		num++;
		try {
			Thread.sleep(50);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("卖出第"+num+"张票,剩余"+tickets+"张票");
	}
}
ackage filecopy;

public class Test {
	public static void main(String[] args) {
		SellTicket r = new SellTicket();
		Thread t1 = new Thread(r,"窗口1");//多线程共同抢占资源;创建线程多个线程;
		Thread t2 = new Thread(r,"窗口2");
		Thread t3 = new Thread(r,"窗口3");
		t1.start();
		t2.start();
		t3.start();
	}
}

5.线程安全相关的类

StringBuilder 线程不安全,但效率高,适合单线程;
StringBuffer 线程安全,但效率低,适合多线程;
HashMap 线程不安全 key可以是null;
Hashtable 线程安全,key 不能是null;
ArrayList 数组列表,非线程安全
Vector 向量,线程安全;

6.死锁

在多线程中,每个线程都拥有对方想要的锁,同时又等待对方给他锁,就会出现死锁问题;
程序中的变现:卡死;
解决方法:使用外力。
原因:同步代码块嵌套所导致;同步代码块可能死锁,但不一定产生死锁;
例如:小花拿到了洋娃娃,小黑拿到了小汽车,小花想要小黑的小汽车然后给小黑洋娃娃,小黑想要小花的洋娃娃然后给小花小汽车;

package practice.executer;

public class Toy {
	public static final Object baby = new Object();
	public static final Object car = new Object();
}

package practice.executer;

public class XiaoHua implements Runnable{

	@Override
	public void run() {
		synchronized (Toy.baby) {
			System.out.println("小花拿了洋娃娃");
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			synchronized (Toy.car) {
				System.out.println("小花拿了小汽车");
			}
		}
	}

}
package practice.executer;

public class XiaoHei implements Runnable{

	@Override
	public void run() {
		synchronized (Toy.car) {
			System.out.println("小黑拿了小汽车");
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			synchronized (Toy.baby) {
				System.out.println("小黑拿了洋娃娃");
			}
		}
	}
}

package practice.executer;

public class Sock {
	public static void main(String[] args) {
		Thread t1 = new Thread(new XiaoHua());
		Thread t2 = new Thread(new XiaoHei());
		t1.start();
		t2.start();
	}
}

在这里插入图片描述

二.线程池

1.线程池的好处

1.线程池可以同一管理线程,减少创建线程、销毁线程的操作,线程的使用率就高。
2.定时、定期执行一定的任务。

2.线程池的使用

都位于java.util.concurrent包,顶级接口Executor执行已提交的Runnable 任务的对象,子接口ExecutorService
抽象类AbstractExecutorService,实现类:ThreadPoolExecutor;
接口ScheduledThreadPoolExecutor,实现类:ScheduledThreadPoolExecutor;
工具类Executors创建线程对象
static ExecutorService newCachedThreadPool()创建可缓存线程的线程池;
static ExecutorService newFixedThreadPool(int nThreads)创建固定线程数的线程池;
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)创建周期执行的线程池。
static ExecutorService newSingleThreadExecutor()创建单线程的线程池。
自定义线程池对象
public ThreadPoolExecutor(int corePoolSize, 核心线程数
int maximumPoolSize, 最大线程数
long keepAliveTime, 最大空闲时间
imeUnit unit,最大空闲时间 使用的单位
BlockingQueue workQueue,阻塞队列,等待的队列
ThreadFactory threadFactory, 线程工厂 ,创建线程
RejectedExecutionHandler handler)拒绝策略

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心尘未泯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值