当前位置:网站首页>线程及线程池

线程及线程池

2022-07-06 09:25:00 手可摘鑫晨

1,线程概念

一个程序运行后至少有一个进程,一个进程中可以包含多个线程。

线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。

2,线程调度

分时调度:所有线程轮流获取CPU的使用权,平均分配每个线程占用的CPU的时间。

抢占式调度:优先级高的线程先使用CPU,如果线程优先级相同,

3,主线程

java使用java.lang.Thread类代表线程,所有线程对象都必须是Thread类或其他子类的实例。每个线程的作用是完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码。Java使用线程执行体来代表这段程序流。

4,实现线程的方式


public class xiancehng {
	public static void main(String[] args) {		
		Thread thread = new SubThread();
		thread.start();			
	}
}
//创建子线程
class SubThread extends Thread {
	@Override
    //重写run方法
	public void run() {
		Thread t = Thread.currentThread();
		String name = t.getName();
		for (int i = 0; i < 10; i++) {
			System.out.println(name + i);
		}
	}
}
public class xiangcheng2 {
	public static void main(String[] args) {
		Runnable runnable = new Runnable() {
			@Override
			public void run() {
				System.out.println("hello word");
			}
		};
		new Thread(runnable).start();
	}
}

5,多线程原理

public class duoxiancheng1 {
	public static void main(String[] args) {
		System.out.println("这里是main线程");
		Thread thread = new ZiThread("小强");
		thread.start();
		for (int i = 0; i < 10; i++) {
			System.out.println("旺财" + i);
		}
	}
}

class ZiThread extends Thread {
	public ZiThread(String name) {
		super(name);
	}

	@Override
	public void run() {
		Thread t = Thread.currentThread();
		String name = t.getName();
		for (int i = 0; i < 10; i++) {
			System.out.println(name + i);
		}
	}
}

 

 6,Thread类

构造方法:

        public Thread();                                                 分配一个新的线程对象

        public Thread(String name);                              分配一个指定名字的新的线程对象

        public Thread(Runnable target);                        分配一个指定目标的新的线程对象

        public Thread(Runnable target,String name);    分配一个指定目标的新的线程对象并指定名字

成员方法:

        public String getName();                                     获取当前线程名称

        public void start();                                               调用线程执行run方法

        public void run();                                                 线程执行的任务在此处定义

        public static void sleep(long millis);                    当前正在执行的线程指定多少毫秒暂停

        public static Thread currentThread();                 返回对当前正在执行的线程对象的引用

7,Thread和Runnable的区别

Runnable的优势:

        1,适合多个线程操作同一个任务对象。

        2,可以避免java中的单继承的局限性。

        3,增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。

        4,线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。可以避免java中的单继承的局限性。

8,匿名内部类方式实现线程的创建

public static void main(String[] args) {
		Runnable r = new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 10; i++) {
					System.out.println(Thread.currentThread().getName() + i);					
				}				
			}
			
		};
		new Thread(r).start();
	}

9,线程安全

案例:电影院要卖票,我们模拟电影院的卖票过程。假设要播放的电影是  我和我的祖国,本次电影的座位共100(本场电影只能卖100张票)

我们来模拟电影院的售票窗口,实现多个窗口同时卖 小猪佩奇这场电影票(多个窗口一起卖这100张票)需要窗口,采用线程对象来模拟;需要票,Runnable接口子类来模拟。

public class xcanq {
	public static void main(String[] args) {
		Ticket ticket = new Ticket();
		new Thread(ticket, "窗口1").start();
		new Thread(ticket, "窗口2").start();
		new Thread(ticket, "窗口3").start();
	}
}

class Ticket implements Runnable {
	private int ticket = 100;
	@Override
	public void run() {
		while (true) {
			synchronized (this) {
				if (ticket > 0) {
					try {
						Thread.sleep(200);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					String name = Thread.currentThread().getName();
					System.out.println(name + "正在卖" + ticket + "张票");
					ticket--;
				}
			}

		}
	}
}

10,Lock锁

使用方法:

        public void lock();

        public void unlock();

11,线程状态

NEW新建状态一个线程创建以后,启动之前,就处于该状态。
TERMINATED消亡状态线程执行完任务后,处于该状态。
RUNNABLE可运行状态线程正在整型任务,就处于该状态。
BLOCKED阻塞状态获取synchronized锁对象失败,处于该状态。
WAITING无限等待状态获取Lock锁对象失败,就处于该状态。
TIMED_WAITING计时等待状态执行sleep方法,就处于该状态。

12,sleep和wait的区别

13,wait和notify方法

(1)wait方法

        线程不再活动,不再参与调度,进入 wait set 中,因此不会浪费 CPU 资源,也不会去竞争锁了,这时的线程状态即是 WAITING。

        它还要等着别的线程执行一个特别的动作,也即是“通知(notify)”在这个对象上等待的线程从wait set 中释放出来,重新进入到调度队列(ready queue)中。

(2)notify方法

        则选取所通知对象的 wait set 中的一个线程释放;例如,餐馆有空位置后,等候就餐最久的顾客最先入座。

(3)notifyAll方法

        释放所通知对象的 wait set 上的全部线程。

注意:

(1)wait方法与notify方法必须要由同一个锁对象调用。因为:对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程。

(2)wait方法与notify方法是属于Object类的方法的。因为:锁对象可以是任意对象,而任意对象的所属类都是继承了Object类的。

(3)wait方法与notify方法必须要在同步代码块或者是同步函数中使用。因为:必须要通过锁对象调用这2个方法。

14,线程的通信

案例:

        包子铺线程生产包子,吃货线程消费包子。当包子没有时(包子状态为false),吃货线程等待,包子铺线程生产包子(即包子状态为true),并通知吃货线程(解除吃货的等待状态),因为已经有包子了,那么包子铺线程进入等待状态。

        接下来,吃货线程能否进一步执行则取决于锁的获取情况。如果吃货获

取到锁,那么就执行吃包子动作,包子吃完(包子状态为false),并通知包子铺线程(解除包子铺的等待状态)吃货线程进入等待。包子铺线程能否进一步执行则取决于锁的获取情况。

定义包子类:

public class Baozi {
	String pier;
	String xianer;
	boolean flag = false;

}

定义吃货线程:

public class Chihuo extends Thread {
	private Baozi bz;
	public Chihuo(String name, Baozi bz) {
		super(name);
		this.bz = bz;
	}

	@Override
	public void run() {
		while (true) {
			synchronized (bz) {
				if (bz.flag == true) {
					System.out.println("吃货正在吃"+bz.pier+bz.xianer+"包子");					
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					bz.flag = false;
					bz.notify();
				} else {
					try {
						bz.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}
	}
}

定义包子铺线程:    

public class BaoZiPu extends Thread {
	private Baozi bz;
	public BaoZiPu(String name, Baozi bz) {
		super(name);
		this.bz = bz;
	}

	@Override
	public void run() {
		int count = 0;
		while (true) {
			synchronized (bz) {
				if (bz.flag == true) {
					try {
						bz.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				} else {
					System.out.println("包子铺开始做包子");
					if (count % 2 == 0) {
						bz.pier = "冰皮";
						bz.xianer = "五仁";
					} else {
						bz.pier = "薄皮";
						bz.xianer = "牛肉大葱";
					}
					count++;
					bz.flag = true;
					System.out.println("包子造好了:" + bz.pier + bz.xianer);
					System.out.println("吃货来吃吧");
					bz.notify();
				}
			}
		}
	}
}

测试线程:

public class Test {
	public static void main(String[] args) {
		Baozi bz = new Baozi();
		Chihuo ch = new Chihuo("吃货", bz);
		BaoZiPu bzp = new BaoZiPu("包子铺",bz);	
		bzp.start();
		ch.start();
	}
}

15,线程池概念

        其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。

16,线程池的好处 

(1)降低资源消耗。减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。

(2)提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。

(3)提高线程的可管理性。可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)

17,线程池的使用

创建线程池:public static ExecutorService newFixedThreadPool(int nThreads)

使用线程池对象:public Future<?> submit(Runnable task)

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class xcc {
	public static void main(String[] args) {
		ExecutorService service = Executors.newFixedThreadPool(2);
		MyRunnable r = new MyRunnable();
		service.submit(r);		
	}
}
class MyRunnable implements Runnable {
	@Override
	public void run() {
		System.out.println("我要一个教练");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("教练来了: " + Thread.currentThread().getName());
		System.out.println("教我游泳,交完后,教练回到了游泳池");
	}
}

    

         

        

 

原网站

版权声明
本文为[手可摘鑫晨]所创,转载请带上原文链接,感谢
https://blog.csdn.net/m0_61562689/article/details/125077213