就是程序运行的单元, 所有的代码都是在线程中执行的
什么是进程程序运行后, 操作系统会分配独立的内存空间, 这块空间是进程, 有自己编号。 可以通过任务管理器, 结束任务, 其本质就是释放这个进程的空间。
并发与并行并行:单位时间片内在同时运行
并行:单位时间片内交替执行
方式一:1.定义一个子类继承(extends)Thread类
2.在子类中重写run方法,并将需要线程开启的代码放入run方法中
3.在测试类中创建Thread子类对象
4.使用子类对象调用start()方法
总结:该方法需要将run方法写进子类代码中,对代码侵入严重,少用。
方式二:1.定义一个实现类,实现Runnable接口
2.重写run()方法,将方法放入run方法中
3.创建Runnable实现类对象
4.创建Thread对象将Runnable实现类对象(也就是任务)放入Thread对象中
5.使用Thread对象调用start方法
注:当然可以使用匿名内部类不过方法太长不建议使用:
Thread thread = new Thread(new Runnable(){
public void run(){
}
}
实现
实现Runnable接口:
public class RedBage implements Runnable {
int count = 3;
int money = 20;
int sumMoney = count*money;
@Override
public void run() {
synchronized (this) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (sumMoney > 0) {
count--;
sumMoney = count*money;
System.out.println("恭喜" + Thread.currentThread().getName() + ",您成功抢到一个20元红包,红包还剩"+count);
} else {
System.out.println(Thread.currentThread().getName() + "抱歉,红包已经被抢完了,红包个数为:"+count);
}
}
}
}
测试类:
public class RedBageDemo {
public static void main(String[] args) {
RedBage redBage = new RedBage();
ArrayList list = new ArrayList<>();
Collections.addAll(list,"黄蓉","瑛姑","黄药师","周伯通","郭靖");
for (int i = 0; i < list.size(); i++) {
//Thread()中的两个参数,redBage:是必须传入的实现类对象,list.get(i)是给线程起名字不重要
//线程的名字可以使用Thread.currentThread().getName()获取,Thread.currentThread()获取当前正在运行线程对象。
Thread thread = new Thread(redBage,list.get(i));
thread.start();
}
}
}
多线程的实现结合线程池
线程池的作用:
解决频繁的创建链接和销毁链接,节约资源和时间。线程池会在池中维护几条线程的存活,当需要调用线程时从线程池中直接使用。
线程池三种创建方式: 方式一:ExecutorService pool = Executors.newCachedThreadPool();
缺点: 没有上限, 消耗大量的内存
ExecutorService pool = Executors.newFixedThreadPool(int count);
缺点: 虽然设定了上限, 但是没有设定闲时的线程的数量
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler
)
//最后两个参数可以不写,使用默认
corePoolSize:核心线程数量 maximumPoolSize:最大线程数量 keepAliveTime:临时线程存活的时间 unit:临时线程存活的时间单位 workQueue:超出任务队列的大小 threadFactory:产生线程的工厂, 目前只有一种方法 Executors.defaultThreadFactory() handler:超出最大任务后的任务如何处理 new ThreadPoolExecutor.AbortPolicy()直接拒绝, 并且报异常 new ThreadPoolExecutor.DiscardPolicy()直接拒绝, 但是不报异常, 最垃圾的!!!!! new ThreadPoolExecutor.DiscardOldestPolicy()直接拒绝等待最久的, 更垃圾 new ThreadPoolExecutor.CallerRunsPolicy()线程不执行, 交给其他线程, main主线程方式三演示使用:
ThreadPoolExecutor pool = new ThreadPoolExecutor(2,3,30, TimeUnit.SECONDS,new ArrayBlockingQueue<>(5));多线程创建:
存在两种情况:1.线程之间没有交互;2.线程之间存在信息交互。直接演示第二种,在第二种情况下对第一种进行解释。
情况二演示:线程间的交互需要用到同步代码块,保证线程的交替执行。作用: 保证一条线程执行代码, 其他线程不能干扰, 能够解决多线程操作共享数据安全问题。当一个线程执行时,另一个线程不能执行,当线程等待时才会释放锁,如何使线程等待:【锁对象.wait()】 。如何唤醒:【锁对象.notifyAll()】;唤醒其他所有线程。例如:
synchronized(锁对象){
//需要同步的代码
}
注意:需要交互的线程的同步代码块的锁对象需要保持统一。
线程一(Runnable接口实现类):public class PersonFirst implements Runnable {
private List list;
private Gift gift;
public PersonFirst(List list, Gift gift) {
this.list = list;
this.gift = gift;
}
//此人false时抢东西
@Override
public void run() {
Random random = new Random();
while (true) {
//同步代码块,锁对象是list
synchronized (list) {
if (gift.isFlag()) {
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
// 抢东西结束
int index = random.nextInt(list.size());
String name = list.remove(index);
System.out.println(Thread.currentThread().getName() + "抢到商品:" + name);
// 更改flag状态
gift.setFlag(true);
// 唤醒其他线程
list.notifyAll();
}
}
}
}
}
线程二:
public class PersonSecond implements Runnable {
//被线程当成锁的对象,可以是任意成员:变量、类对象都可以但要保证唯一性。
private List list;
private Gift gift;
public PersonSecond(List list, Gift gift) {
this.list = list;
this.gift = gift;
}
//此人true时抢东西
@Override
public void run() {
Random random = new Random();
while (true) {
//与线程一的锁对象是同一个对象
synchronized (list) {
if (!gift.isFlag()) {
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
// 抢东西结束
int index = random.nextInt(list.size());
String name = list.remove(index);
System.out.println(Thread.currentThread().getName() + "抢到商品:" + name);
// 更改flag状态
gift.setFlag(false);
// 唤醒其他线程
list.notifyAll();
}
}
}
}
}
线程间交流状态的对象:
public class Gift {
private boolean flag;
public Gift() {
}
public Gift(boolean flag) {
this.flag = flag;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
测试类:
public class Test {
public static void main(String[] args) {
String[] arr = {"海尔冰箱", "鸟牌电视机", "苏泊尔炒锅", "美的电饭煲", "小新文具", "想你美被罩", "华为mate40手机", "小米拖鞋"};
ArrayList list = new ArrayList<>();
List strings = Collections.synchronizedList(list);
Collections.addAll(list,arr);
Gift gift = new Gift(true);
// 创建两个线程任务
ThreadPoolExecutor pool = new ThreadPoolExecutor(2,3,30, TimeUnit.SECONDS,new ArrayBlockingQueue<>(5));
PersonFirst personFirst = new PersonFirst(list, gift);
PersonSecond personSecond = new PersonSecond(list, gift);
// 将任务发给线程池
pool.submit(personFirst);
pool.submit(personSecond);
}
}
单独多线程的使用:
将同步代码块取消即可,此时线程的执行变为无序状态,那个线程先抢到资源那个线程执行。
可以直接用:
PersonFirst personFirst = new PersonFirst(list, gift);
PersonSecond personSecond = new PersonSecond(list, gift);
Thread thread1 = new Thread(personFirst);
Thread thread2 = new Thread(personSecond);
thread1.start();
thread2.start();
//放入线程池执行
ThreadPoolExecutor pool = new ThreadPoolExecutor(2,3,30, TimeUnit.SECONDS,new ArrayBlockingQueue<>(5));
pool.submit(personFirst);
pool.submit(personSecond);
方法改进使用单例模式,确保一个类的对象只能被创建一次
单例模式:
1.保证一个类只有一个对象(实例)
2.作用:因为对象只有一个,可以用来共享数据,省去传参给多个类的过程。
饿汉式:
1.私有化构造
2.维护一个private static 修饰的本类对象
3.提供一个static修饰的get方法返回本类对象
实现,例如:
public class Desk {
private Desk() {
}
private static Desk desk = new Desk();
public static Desk getDesk() {
return desk;
}
}
懒汉式:
1.私有化构造
2.维护private static 本类引用
3.提供静态的get方法, 在方法内部判断对象是否为null
4.存在的风险:
可能出现线程安全问题。
5.如何解决:加上同步锁
synchronized(锁对象){
//需要同步的代码
}
代码实现:
Desk单例:
public class Desk {
private boolean flag = false;
private static Desk desk = new Desk();
private Desk() {
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public static Desk getDesk() {
return desk;
}
}
线程一:
public class Cook implements Runnable {
@Override
public void run() {
while (true) {
//Desk.getDesk()获取Desk对象,使用了单例模式
synchronized (Desk.getDesk()) {
if (Desk.getDesk().isFlag()) {
try {
Desk.getDesk().wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"蒸包子");
Desk.getDesk().setFlag(!Desk.getDesk().isFlag());
Desk.getDesk().notifyAll();
}
}
}
}
}
线程二:
public class Eator implements Runnable{
@Override
public void run() {
while (true){
//同样是单例操作的是同一个对象
synchronized (Desk.getDesk()){
if (!Desk.getDesk().isFlag()){
try {
Desk.getDesk().wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"吃包子");
Desk.getDesk().setFlag(!Desk.getDesk().isFlag());
Desk.getDesk().notifyAll();
}
}
}
}
}
Test类:
public class Test {
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(5, 7, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5));
pool.submit(new Cook());
pool.submit(new Eator());
}
}



