6. 多线程工作原理
操作系统管理线程,是以时间片(time pieces)为单位来管理线程。
① 操作系统将时间划分为很短的一块,这个时间又是随机分配,当程序运行时,CPU就将这个程序中的多个线程放入一个叫线程池的空间中。
② 当线程准备完毕后,操作系统中的线程调度器就会从线程池中根据线程的随机顺序来挑选某个线程,让CPU来执行此线程。而执行此线程的事件就是上一步所说的某个时间片。
/**
* 多线程工作原理【多个线程是交替运行着的】
*/
public class TestThread01 {
public static void main(String[] args) {
new Thread01().start();
new Thread02().start();
}
private static class Thread01 extends Thread{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
try {
Thread.sleep(2);
System.out.println(Thread.currentThread().getName() + "线程正在运行!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private static class Thread02 extends Thread{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
try {
Thread.sleep(2);
System.out.println(Thread.currentThread().getName() + "线程正在运行!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
7. 实现多线程的四种方式
现多线程的四种方式:
1、Thread
2、Runnable
3、Callable + FutureTask
4、线程池
public class TestThread02 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 第一种方法,继承Thread类
new Thread01().start();
new Thread01().start();
new Thread01().start();
// 第二种方法:实现Runnable接口
Thread02 thread02 = new Thread02();
new Thread(thread02).start();
new Thread(thread02).start();
new Thread(thread02).start();
// 第二种方法的lambda表达式方法
Runnable runnable = new Thread(){
int i = 1;
@Override
public void run() {
System.out.println("i = " + i++);
}
};
new Thread(runnable).start();
new Thread(runnable).start();
new Thread(runnable).start();
// 第三种:使用Callable接口 + FutureTask接口
FutureTask<Integer> task = new FutureTask<>(new Callable<Integer>(){
int i = 10;
@Override
public Integer call() throws Exception {
return i + 1;
}
});
new Thread(task).start();
System.out.println(task.get());
}
// 方法一:继承Thread类
private static class Thread01 extends Thread {
int i = 1;
@Override
public void run() {
System.out.println("i = " + i++);
}
}
// 方法二:实现Runnable接口
private static class Thread02 implements Runnable {
int i = 1;
@Override
public void run() {
System.out.println("i = " + i++);
}
}
}
小结:
1、继承自 Thread 类实现多线程的原理图:
2、实现 Ruunable 接口的方式实现的多线程,可以实现资源的共享。
两种实现多线程的机制,第二种可以实现资源的共享,并且对原来的类没有任何污染,而第一种方式,因为己经继承了一个类,受 java 单根继承的影响,所以不能再继承其它类,即这种方式对原来的类进行了污染。
8. 线程优先级、礼让、休眠
8.1 线程优先级
public class ThreadPriority {
/**
* 线程的优先级只能由操作系统决定,Java只能在语言级提供建议权,没有决定权
* @param args
*/
public static void main(String[] args) {
Thread03 thread03 = new Thread03();
Thread04 thread04 = new Thread04();
// 程序只是建议优先执行thread04线程,具体先执行哪个由操作系统决定
thread04.setPriority(Thread.MAX_PRIORITY);
thread03.setPriority(Thread.MIN_PRIORITY);
thread03.start();
thread04.start();
}
private static class Thread03 extends Thread{
@Override
public void run() {
System.out.println("线程一正在运行。。。");
}
}
private static class Thread04 extends Thread{
@Override
public void run() {
System.out.println("线程二正在运行。。。");
}
}
}
8.2 线程礼让
public class TestYield {
/**
* 线程礼让yield,代表将自己的执行权让出,重新回到线程池种,
* 再次接受CPU的调度,也有再次被选中执行的可能性。
*/
public static void main(String[] args) {
new Thread01().start();
new Thread01().start();
}
private static class Thread01 extends Thread{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
if (i % 50 == 0){
Thread.yield();
System.out.println("i=" + i + ",当前线程:" + Thread.currentThread().getName() + "正在运行。。。");
}
}
}
}
}
8.3 线程休眠
/**
* 线程休眠:线程处于一种阻塞(blocked)状态
*/
public class TestSleep {
public static void main(String[] args) throws IOException {
Thread01 thread01 = new Thread01();
thread01.start();
System.in.read();
thread01.interrupt(); // 打断休息
}
public static class Thread01 extends Thread{
@Override
public void run() {
try {
Thread.sleep(10000);
System.out.println("休息中。。。");
} catch (InterruptedException e) {
System.out.println("不要打扰我休息!");
return;
}
System.out.println("正常休息结束。");
}
}
}
9. 线程同步
9.1 同步代码块
public class TestSync {
public static void main(String[] args) {
Thread01 thread01 = new Thread01();
new Thread(thread01).start();
new Thread(thread01).start();
new Thread(thread01).start();
}
/**
* 火车站同时3个窗口卖票
*/
private static class Thread01 implements Runnable{
// 100张火车票
int tickets = 100;
@Override
public void run() {
while (true){
// 实现线程同步的方法一:同步代码块中的锁(监视器对象)可以是任意对象
synchronized (this){
if (tickets > 0){
try {
Thread.sleep(10);
System.out.println("线程" + Thread.currentThread().getName() + "正在售第" + tickets-- + "张票!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
break;
}
}
}
}
}
}
9.2 同步方法
public class TestSync {
public static void main(String[] args) {
Thread01 thread01 = new Thread01();
new Thread(thread01).start();
new Thread(thread01).start();
new Thread(thread01).start();
}
/**
* 火车站同时3个窗口卖票
*/
private static class Thread01 implements Runnable{
// 100张火车票
int tickets = 100;
@Override
public void run() {
while (true){
// 实现线程同步的方法二:同步方法实现线程同步
boolean b = sellTickets();
if (!b){
break;
}
}
}
private synchronized boolean sellTickets() {
if (tickets > 0){
try {
Thread.sleep(10);
System.out.println("线程" + Thread.currentThread().getName() + "正在售第" + tickets-- + "张票!");
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}
return false;
}
}
}
小结:
两种实现线程同步方法,使用同步方法的监视器对象只能是 this,而使用同步代码块的方式其监视器对象可以是任意对象。
10. 栈-Stack 类的用法
栈的特点:先进后出,后进先出
/**
* 栈Stack用法
*/
public class TestStack {
public static void main(String[] args) {
Stack<String> stack = new Stack<>();
// 入栈:向栈中存放数据
stack.push("aa");
stack.push("bb");
stack.push("cc");
stack.push("dd");
stack.push("ee");
// 出栈:从栈中弹出数据(取走了)
String pop = stack.pop();
System.out.println("pop = " + pop);
// 查看栈顶元素(元素还在)
String peek = stack.peek();
System.out.println("peek = " + peek);
// elementAt()代表可以根据下标位置取出元素
String elementAt = stack.elementAt(0);
System.out.println("elementAt = " + elementAt);
// get()代表可以根据下标取出元素
String str = stack.get(0);
System.out.println("str = " + str);
// 查看栈内元素大小
int size = stack.size();
System.out.println("size = " + size);
}
}
11. 生产者与消费者
/**
* 生产者和消费者
*/
public class TestProducerConsumer {
public static void main(String[] args) {
// 定义盒子
Stack<Integer> stack = new Stack<>();
// 启动生产者线程
new Producer(stack).start();
// 启动消费者线程
new Consumer(stack).start();
}
/**
* 生产者线程
*/
private static class Producer extends Thread{
private Stack<Integer> stack;
public Producer(Stack<Integer> stack) {
this.stack = stack;
}
@Override
public void run() {
Random random = new Random();
while (true){
synchronized (stack){
if (stack.size() < 20){
// 产生一个[0,100)的随机数
int num = random.nextInt(100);
// 入栈
this.stack.push(num);
System.out.println("正在生产:" + num);
}else {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
/**
* 消费者线程
*/
private static class Consumer extends Thread{
private Stack<Integer> stack;
public Consumer(Stack<Integer> stack) {
this.stack = stack;
}
@Override
public void run() {
Random random = new Random();
while (true){
synchronized (stack){
if (stack.size() > 0){
// 出栈
Integer pop = stack.pop();
System.out.println("正在出栈:" + pop);
}else {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
}