前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >第二十五天 多线程-常用方法&线程池【悟空教程】

第二十五天 多线程-常用方法&线程池【悟空教程】

作者头像
Java帮帮
发布2018-07-26 16:04:21
3470
发布2018-07-26 16:04:21
举报

第二十五天 多线程-常用方法&线程池【悟空教程】

第25天 多线程

第1章 多线程常用方法

1.1 多线程常用方法

1.1.1 常规方法:

  • public final String getName() 返回该线程的名称。
  • public final void setName(String name)
  • public static Thread currentThread() 返回的就是当前的执行线程
  • public void run()
  • public void start()
  • 重写public String toString()

继承Thread方法:

public class MyThread extends Thread {

//重写 run

@Override

public void run() {

for (int i = 0; i < 1000 ; i++) {

System.out.println(getName() + " ==== " + i );

}

}

}

/*

* 多线程 简单方法:

* String getName() 返回该线程的名称。

* void setName(String name) 设置线程名称

* Thread currentThread() , 返回的就是当前的执行线程.

*/

public class Demo {

public static void main(String[] args) {

// 创建 MyThread 对象

MyThread mt1 = new MyThread();

MyThread mt2 = new MyThread();

mt1.setName("姚明");

mt2.setName("郭敬明");

mt1.start();

mt2.start();

}

}

实现Runnable接口

public class MyRunnable implements Runnable {

@Override

public void run() {

for (int i = 1000; i >= 0; i--) {

// 获取当前方法的执行线程

Thread currentThread = Thread.currentThread(); // 执行当前的方法的线程对象.

System.out.println(currentThread.getName() + " ==== " + i);

}

}

}

public class Demo {

public static void main(String[] args) {

//创建 子类对象

MyRunnable myRunnable = new MyRunnable();

//创建线程对象

Thread thread = new Thread(myRunnable);

Thread thread2 = new Thread(myRunnable);

thread.setName("XXX");

thread2.setName("AAA");

// 开启线程

thread.start();

thread2.start();

Thread currentThread = Thread.currentThread();

currentThread.setName("^(* ̄(oo) ̄)^");

System.out.println(currentThread.getName());

}

}

1.1.2 线程操作方法:

1.1.2.1 优先级

public final void setPriority(int newPriority) 设置优先级,取值:1-10

public final int getPriority() 获取优先级

/*

public final void setPriority(int newPriority) 设置优先级,取值:1-10

public final int getPriority() 获取优先级

*/

public class Demo2 {

public static void main(String[] args) {

Thread currentThread = Thread.currentThread();

System.out.println(currentThread);

int priority = currentThread.getPriority();

System.out.println(priority); // 默认是 5 ,最小 1 ,最大10;

MyThread myThread = new MyThread();

myThread.setPriority(10);

myThread.start();

for (int i = 0; i < 1000 ; i++) {

System.out.println("main ---" + i);

}

}

}

1.1.2.2 线程加入&守护线程

public final void join() throws InterruptedException 线程加入(插队,加入方法)

public final void setDaemon(boolean on) 设置守护线程(坦克大战,守护main)

public class T1 extends Thread {

@Override

public void run() {

for (int i = 0; i < 1000; i++) {

if (i == 200) {

// 加入另外一条线程

try {

T2 t2 = new T2();

t2.start();

t2.join(); // 加入方法, 就是插队.

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

System.out.println(i + " ==== t1" );

}

}

}

public class T2 extends Thread {

@Override

public void run() {

for (int i = 0; i < 500 ; i++) {

System.out.println(" t2 ---- " + i );

}

}

}

/*

* join . 加入

* setDaemon(boolean on) 设置守护线程

*

*/

public class Demo3 {

public static void main(String[] args) {

T1 t1 = new T1();

t1.setDaemon(true); // t1 就是守护线程 了

t1.start();

for (int i = 0; i < 10; i++) {

System.out.println(i); // 主线程 一完成, 守护也就结束.

}

}

}

public void interrupt() 被中断的线程会报被中断异常,这时需要使用try/catch语句解决相关问题,线程后代码仍然可以继续执行

public final void stop() (已过时) 直接停止线程,线程后代码无法被执行

1.1.2.3 线程睡眠(到指定时间自动恢复)

public static void sleep(long millis) throws InterruptedException

/*

* public static void sleep(long millis) 睡眠 .

*/

public class Demo {

public static void main(String[] args) {

for (int i = 10; i > 0; i--) {

// 暂停

try {

Thread.sleep(10000); // 到指定的时间,自动醒过来.

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(i);

}

System.out.println("点火 ");

}

}

1.2 测试JVM多线程_垃圾回收线程

/*

* 获取垃圾回收线程的名字.

*/

public class Demo {

public static void main(String[] args) {

for (int i = 0; i < 100000; i++) {

new Person();

System.out.println(i);

}

}

}

public class Person {

public Person() {

System.out.println(" 我来了, HELLO==WORLD");

}

@Override

protected void finalize() throws Throwable {

System.out.println(" 我是 垃圾 了, 我挂了, ByeBye World ");

Thread currentThread = Thread.currentThread();

System.out.println(currentThread.getName());

}

}

1.3 等待唤醒机制

在开始讲解等待唤醒机制之前,有必要搞清一个概念——线程之间的通信:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。通过一定的手段使各个线程能有效的利用资源。而这种手段即—— 等待唤醒机制。

等待唤醒机制所涉及到的方法:

  • wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中。
  • notify():唤醒,唤醒线程池中被wait()的线程,一次唤醒一个,而且是任意的。
  • notifyAll(): 唤醒全部:可以将线程池中的所有wait() 线程都唤醒。

其实,所谓唤醒的意思就是让 线程池中的线程具备执行资格。必须注意的是,这些方法都是在 同步中才有效。同时这些方法在使用时必须标明所属锁,这样才可以明确出这些方法操作的到底是哪个锁上的线程。

仔细查看JavaAPI之后,发现这些方法 并不定义在 Thread中,也没定义在Runnable接口中,却被定义在了Object类中,为什么这些操作线程的方法定义在Object类中?

因为这些方法在使用时,必须要标明所属的锁,而锁又可以是任意对象。能被任意对象调用的方法一定定义在Object类中。

接下里,我们先从一个简单的示例入手:

如上图说示,输入线程向Resource中输入name ,sex , 输出线程从资源中输出,先要完成的任务是:

  • 1.当input发现Resource中没有数据时,开始输入,输入完成后,叫output来输出。如果发现有数据,就wait();
  • 2.当output发现Resource中没有数据时,就wait() ;当发现有数据时,就输出,然后,叫醒input来输入数据。

下面代码,模拟等待唤醒机制的实现:

  • 模拟资源类

public class Resource {

private String name;

private String sex;

private boolean flag = false;

public synchronized void set(String name, String sex) {

if (flag)

try {

wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

// 设置成员变量

this.name = name;

this.sex = sex;

// 设置之后,Resource中有值,将标记该为 true ,

flag = true;

// 唤醒output

this.notify();

}

public synchronized void out() {

if (!flag)

try {

wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

// 输出线程将数据输出

System.out.println("姓名: " + name + ",性别: " + sex);

// 改变标记,以便输入线程输入数据

flag = false;

// 唤醒input,进行数据输入

this.notify();

}

}

  • 输入线程任务类

public class Input implements Runnable {

private Resource r;

public Input(Resource r) {

this.r = r;

}

@Override

public void run() {

int count = 0;

while (true) {

if (count == 0) {

r.set("小明", "男生");

} else {

r.set("小花", "女生");

}

// 在两个数据之间进行切换

count = (count + 1) % 2;

}

}

}

  • 输出线程任务类

public class Output implements Runnable {

private Resource r;

public Output(Resource r) {

this.r = r;

}

@Override

public void run() {

while (true) {

r.out();

}

}

}

  • 测试类

public class ResourceDemo {

public static void main(String[] args) {

// 资源对象

Resource r = new Resource();

// 任务对象

Input in = new Input(r);

Output out = new Output(r);

// 线程对象

Thread t1 = new Thread(in);

Thread t2 = new Thread(out);

// 开启线程

t1.start();

t2.start();

}

}

1.4 线程生命周期

第2章 线程池

2.1 线程池概念

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

我们详细的解释一下为什么要使用线程池?

在java中,如果每个请求到达就创建一个新线程,开销是相当大的。在实际使用中,创建和销毁线程花费的时间和消耗的系统资源都相当大,甚至可能要比在处理实际的用户请求的时间和资源要多的多。除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源。如果在一个jvm里创建太多的线程,可能会使系统由于过度消耗内存或“切换过度”而导致系统资源不足。为了防止资源不足,需要采取一些办法来限制任何给定时刻处理的请求数目,尽可能减少创建和销毁线程的次数,特别是一些资源耗费比较大的线程的创建和销毁,尽量利用已有对象来进行服务。

线程池主要用来解决线程生命周期开销问题和资源不足问题。通过对多个任务重复使用线程,线程创建的开销就被分摊到了多个任务上了,而且由于在请求到达时线程已经存在,所以消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使用应用程序响应更快。另外,通过适当的调整线程中的线程数目可以防止出现资源不足的情况。

2.2 使用线程池方式--Runnable接口

通常,线程池都是通过线程池工厂创建,再调用线程池中的方法获取线程,再通过线程去执行任务方法。

  • Executors:线程池创建工厂类
    • public static ExecutorService newFixedThreadPool(int nThreads):返回线程池对象
  • ExecutorService:线程池类
    • Future<?> submit(Runnable task):获取线程池中的某一个线程对象,并执行
  • Future接口:用来记录线程任务执行完毕后产生的结果。线程池创建与使用
  • 使用线程池中线程对象的步骤:
    • 创建线程池对象
    • 创建Runnable接口子类对象
    • 提交Runnable接口子类对象
    • 关闭线程池

代码演示:

public class ThreadPoolDemo {

public static void main(String[] args) {

//创建线程池对象

ExecutorService service = Executors.newFixedThreadPool(2);//包含2个线程对象

//创建Runnable实例对象

MyRunnable r = new MyRunnable();

//自己创建线程对象的方式

//Thread t = new Thread(r);

//t.start(); ---> 调用MyRunnable中的run()

//从线程池中获取线程对象,然后调用MyRunnable中的run()

service.submit(r);

//再获取个线程对象,调用MyRunnable中的run()

service.submit(r);

service.submit(r);

//注意:submit方法调用结束后,程序并不终止,是因为线程池控制了线程的关闭。将使用完的线程又归还到了线程池中

//关闭线程池

//service.shutdown();

}

}

  • Runnable接口实现类

public 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("教我游泳,交完后,教练回到了游泳池");

}

}

2.3 使用线程池方式—Callable接口

  • Callable接口:与Runnable接口功能相似,用来指定线程的任务。其中的call()方法,用来返回线程任务执行完毕后的结果,call方法可抛出异常。
  • ExecutorService:线程池类
    • <T> Future<T> submit(Callable<T> task):获取线程池中的某一个线程对象,并执行线程中的call()方法
  • Future接口:用来记录线程任务执行完毕后产生的结果。线程池创建与使用
  • 使用线程池中线程对象的步骤:
    • 创建线程池对象
    • 创建Callable接口子类对象
    • 提交Callable接口子类对象
    • 关闭线程池

代码演示:

public class ThreadPoolDemo {

public static void main(String[] args) {

//创建线程池对象

ExecutorService service = Executors.newFixedThreadPool(2);//包含2个线程对象

//创建Callable对象

MyCallable c = new MyCallable();

//从线程池中获取线程对象,然后调用MyRunnable中的run()

service.submit(c);

//再获取个教练

service.submit(c);

service.submit(c);

//注意:submit方法调用结束后,程序并不终止,是因为线程池控制了线程的关闭。将使用完的线程又归还到了线程池中

//关闭线程池

//service.shutdown();

}

}

  • Callable接口实现类,call方法可抛出异常、返回线程任务执行完毕后的结果

public class MyCallable implements Callable {

@Override

public Object call() throws Exception {

System.out.println("我要一个教练:call");

Thread.sleep(2000);

System.out.println("教练来了: " +Thread.currentThread().getName());

System.out.println("教我游泳,交完后,教练回到了游泳池");

return null;

}

}

2.4 线程池练习:返回两个数相加的结果

要求:通过线程池中的线程对象,使用Callable接口完成两个数求和操作

  • Future接口:用来记录线程任务执行完毕后产生的结果。线程池创建与使用
    • V get() 获取Future对象中封装的数据结果

代码演示:

public class ThreadPoolDemo {

public static void main(String[] args) throws InterruptedException, ExecutionException {

//创建线程池对象

ExecutorService threadPool = Executors.newFixedThreadPool(2);

//创建一个Callable接口子类对象

//MyCallable c = new MyCallable();

MyCallable c = new MyCallable(100, 200);

MyCallable c2 = new MyCallable(10, 20);

//获取线程池中的线程,调用Callable接口子类对象中的call()方法, 完成求和操作

//<Integer> Future<Integer> submit(Callable<Integer> task)

// Future 结果对象

Future<Integer> result = threadPool.submit(c);

//此 Future 的 get 方法所返回的结果类型

Integer sum = result.get();

System.out.println("sum=" + sum);

//再演示

result = threadPool.submit(c2);

sum = result.get();

System.out.println("sum=" + sum);

//关闭线程池(可以不关闭)

}

}

  • Callable接口实现类

public class MyCallable implements Callable<Integer> {

//成员变量

int x = 5;

int y = 3;

//构造方法

public MyCallable(){

}

public MyCallable(int x, int y){

this.x = x;

this.y = y;

}

@Override

public Integer call() throws Exception {

return x+y;

}

}

第3章 多线程总结

  • 同步锁

多个线程想保证线程安全,必须要使用同一个锁对象

  • 同步代码块

synchronized (锁对象){

可能产生线程安全问题的代码

}

同步代码块的锁对象可以是任意的对象

  • 同步方法

public synchronized void method()

可能产生线程安全问题的代码

}

同步方法中的锁对象是 this

  • 静态同步方法

public synchronized void method()

可能产生线程安全问题的代码

}

静态同步方法中的锁对象是 类名.class

  • 多线程有几种实现方案,分别是哪几种?

a, 继承Thread类

b, 实现Runnable接口

c, 通过线程池,实现Callable接口

  • 同步有几种方式,分别是什么?

a,同步代码块

b,同步方法

静态同步方法

  • 启动一个线程是run()还是start()?它们的区别?

启动一个线程是start()

区别:

start: 启动线程,并调用线程中的run()方法

run : 执行该线程对象要执行的任务

  • sleep()和wait()方法的区别

sleep: 不释放锁对象, 释放CPU使用权

在休眠的时间内,不能唤醒

wait(): 释放锁对象, 释放CPU使用权

在等待的时间内,能唤醒

  • 为什么wait(),notify(),notifyAll()等方法都定义在Object类中

锁对象可以是任意类型的对象

第4章 本日自习作业:

4.1 知识点相关题

4.1.1 请描述并画出线程生命周期图,越详细越好

4.1.2 简单使用一次今天介绍的线程方法

4.1.3 使用线程池完成多线程卖票

4.1.4 启动一个线程是用run()还是start()?

启动一个线程是调用start()方法,使线程就绪状态,以后可以被调度为运行状态,一个线程必须关联一些具体的执行代码,run()方法是该线程所关联的执行代码。

4.1.5 用实现runable接口的方式创建创建一个多线程买票小程序,使用卖票的例子引出线程安全问题(用sleep()方法)并用synchronized代码块解决线程安全问题。

答案:

代码语言:javascript
复制
public class Ticket implements Runnable {

//多个对象 共享同一个资源, 需要static修饰

private int ticket = 100;

//创建锁对象(可以是任意对象)

private Object obj = new Object();



@Override

public void run() {

while (true) {

synchronized ( obj ){

if (ticket >0) {

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName()+":正在卖第 "+ ticket-- +"张

票");

}

}

}

}

}

public class SellTicket {

public static void main(String[] args) {

//创建自定义类对象

Ticket ticket = new Ticket();

//创建线程对象

Thread t1 = new Thread(ticket, "窗口1");

Thread t2 = new Thread(ticket, "窗口2");

Thread t3 = new Thread(ticket, "窗口3");

//启动线程

t1.start();

t2.start();

t3.start();

}

}

4.1.6 能够理解死锁的概念。

4.1.7 理解什么是线程间通信

其实就是多个线程在操作同一个资源,但是操作的动作不同。如果一个进程中的所有线程都不需要相互传递数据就可以顺利完成,那么程序运行的性能自然是最好的,但是实际上,很少有现成能够在所有的时间都独立的进行操作,通常在以下两种情况下,线程之间需要进行通信。 多个线程都对共享资源资源进行访问,但不希望共享资源被破坏。 一个线程完成了任务,要通知其他的线程。

4.1.8 多线程有几种实现方法?同步有几种实现方法?

多线程有两种实现方法,分别是继承Thread类与实现Runnable接口

同步的实现方面有两种,分别是synchronized,wait与notify

wait():使一个线程处于等待状态,并且释放所持有的对象的lock。

sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。

notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。

Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。

4.2 代码题

4.2.1 使用线程池完成以下功能(线程池的线程个数为2):

1、通过一个线程获取一个0-100内的随机数并在将随机数返回到main方法中,在main方法中将该随机数添加到list集合中;

2、将该任务向线程池提交3次,每次生成随机数之前让线程休眠1000毫秒,然后打印“”“线程XXXX生成的随机数为:XXX”;

3、在main方法中打印集合的内容

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;

public class Demo {

public static void main(String[] args) throws InterruptedException, ExecutionException {

m2();

}

public static void m2() throws InterruptedException, ExecutionException{

//1、使用线程池工厂创建线程池对象

ExecutorService pool = Executors.newFixedThreadPool(2);

//2、向线程池中提交任务

MyCallable my = new MyCallable();

List<Integer> list = new ArrayList<Integer>();

for(int i=0;i<3;i++){

//循环向线程池中提交任务

Future<Integer> s1 = pool.submit(my);

//解析线程执行的结果

Integer num1 = s1.get();

list.add(num1);

}

System.out.println(list);

//5、关闭线程池(可关可不关)

pool.shutdown();

}

}

public class MyCallable implements Callable<Integer>{

@Override

public Integer call() throws Exception {

Thread thread = Thread.currentThread();

thread.sleep(1000);

int i = new Random().nextInt(100);

System.out.println("线程:"+thread.getName()+"生成的随机数为:"+i);

return i;

}

}

4.2.2 创建线程计算 1--100的和,并将结果返回给主线程

答案:

代码语言:javascript
复制
public class Test02 {

public static void main(String[] args) throws InterruptedException, ExecutionException {

ExecutorService es = Executors.newSingleThreadExecutor();

//创建的是Callable对象

Future<Integer> f = es.submit(new Callable<Integer>() {

 

@Override

public Integer call() throws Exception {

//求和并返回结果

int sum = 0;

for(int i = 1; i <= 100; i++){

sum += i;

}

return sum;

}

});

//获取结果

System.out.println(f.get());

es.shutdown();

}

}

4.2.3 写出一个锁嵌套的死锁代码

  • 定义锁对象类

public class MyLock {

public static final Object lockA = new Object();

public static final Object lockB = new Object();

}

  • 线程任务类

public class ThreadTask implements Runnable {

int x = new Random().nextInt(1);//0,1

//指定线程要执行的任务代码

@Override

public void run() {

while(true){

if (x%2 ==0) {

//情况一

synchronized (MyLock.lockA) {

System.out.println("if-LockA");

synchronized (MyLock.lockB) {

System.out.println("if-LockB");

System.out.println("if大口吃肉");

}

}

} else {

//情况二

synchronized (MyLock.lockB) {

System.out.println("else-LockB");

synchronized (MyLock.lockA) {

System.out.println("else-LockA");

System.out.println("else大口吃肉");

}

}

}

x++;

}

}

}

  • 测试类

public class ThreadDemo {

public static void main(String[] args) {

//创建线程任务类对象

ThreadTask task = new ThreadTask();

//创建两个线程

Thread t1 = new Thread(task);

Thread t2 = new Thread(task);

//启动线程

t1.start();

t2.start();

}

}

4.2.4 生产一个,消费一个;等待唤醒机制(单生产者单消费者)

答案:

代码语言:javascript
复制
public class Phone {

private String bland; //型号

private String color; //颜色

private boolean isNewPhone = false;//是否有新手机



//购买手机

public synchronized void get(){

//判断是否有新手机

if (!this.isNewPhone) {

//进来了,代表没有新手机

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

//代码执行到了这里, 说明此刻有新手机

//购买手机

System.out.println("购买了 :" + this.bland + "..." + this.color);

//更新新 手机的状态

this.isNewPhone = false;

//通知生产商, 没有新手机了, 要生产新手机

this.notify();

}



//生产手机

public synchronized void set(String bland, String color){

//判断是否有新手机

if (this.isNewPhone) {

//进来了,代表有手机

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}



//如果走到了这个位置, 说明当前没有新手机

//生产一部新手机

this.bland = bland;

this.color = color;

System.out.println("生产了:" + this.bland + "---" + this.color);



//更新手机的状态为 有新手机

this.isNewPhone = true;

//通知消费者,有新手机了,可以购买

this.notify();

}

}

/*

* 生产商

*/

public class SetPhone implements Runnable {

private Phone phone;

int num = 0;



public SetPhone(Phone phone){

this.phone = phone;

}



@Override

public void run() {

//生产手机

while(true){

//生产一部新手机

if (num%2==0) {

phone.set("Iphone6 Plus", "土豪金");

} else {

phone.set("金立语音王", "红色");

}

num++;

}

}

}

/*

* 消费者类(顾客)

*/

public class GetPhone implements Runnable {

private Phone phone;

public GetPhone(Phone phone){

this.phone = phone;

}



@Override

public void run() {

while(true){

phone.get();

}

}

}

/*

* 测试类

*/

 

public class PhoneTest {

public static void main(String[] args) {

//定义一个手机对象

Phone phone = new Phone();



SetPhone setPhone = new SetPhone(phone);

GetPhone getPhone = new GetPhone(phone);

//创建线程对象

Thread setThread = new Thread(setPhone);

Thread getThread = new Thread(getPhone);

//启动线程

setThread.start();

getThread.start();

}

}

4.2.5 现有红包个数共50个,模拟三个人在抢红包过程

每个人相当于一条线程(需要给三个命名),每次抢到的红包随机为1-10元,要求每人每次只能抢一个红包,抢红包的过程中需要睡眠300毫秒,并且抢完的人还可以继续参与抢红包.抢到红包后在控制台打印输出”XXX线程抢到第X个红包,红包金额为X元,还剩余X个红包...”,另外在所有红包抢完后提示”红包已抢完”,程序结束.(要求使用Thread类和Runnable中的一种方式去实现).

4.2.6 一共有1000份盒饭,可以在两个窗口领取,假设每次装盒饭的时间为3000毫秒请用线程模拟取饭过程并打印剩余盒饭数量(分别设置线程名称 窗口一,窗口二).

4.2.7 同时开启两个线程(并且设置线程名称),共同输出1-10之间的所有数字,并且将输出偶数的线程名称打印出来。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-06-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java帮帮 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第1章 多线程常用方法
    • 1.1 多线程常用方法
      • 1.1.1 常规方法:
      • 1.1.2 线程操作方法:
    • 1.2 测试JVM多线程_垃圾回收线程
      • 1.3 等待唤醒机制
        • 1.4 线程生命周期
        • 第2章 线程池
          • 2.1 线程池概念
            • 2.2 使用线程池方式--Runnable接口
              • 2.3 使用线程池方式—Callable接口
                • 2.4 线程池练习:返回两个数相加的结果
                • 第3章 多线程总结
                • 第4章 本日自习作业:
                  • 4.1 知识点相关题
                    • 4.1.1 请描述并画出线程生命周期图,越详细越好
                    • 4.1.2 简单使用一次今天介绍的线程方法
                    • 4.1.3 使用线程池完成多线程卖票
                    • 4.1.4 启动一个线程是用run()还是start()?
                    • 4.1.5 用实现runable接口的方式创建创建一个多线程买票小程序,使用卖票的例子引出线程安全问题(用sleep()方法)并用synchronized代码块解决线程安全问题。
                    • 4.1.6 能够理解死锁的概念。
                    • 4.1.7 理解什么是线程间通信
                    • 4.1.8 多线程有几种实现方法?同步有几种实现方法?
                  • 4.2 代码题
                    • 4.2.1 使用线程池完成以下功能(线程池的线程个数为2):
                    • 4.2.2 创建线程计算 1--100的和,并将结果返回给主线程
                    • 4.2.3 写出一个锁嵌套的死锁代码
                    • 4.2.4 生产一个,消费一个;等待唤醒机制(单生产者单消费者)
                    • 4.2.5 现有红包个数共50个,模拟三个人在抢红包过程
                    • 4.2.6 一共有1000份盒饭,可以在两个窗口领取,假设每次装盒饭的时间为3000毫秒请用线程模拟取饭过程并打印剩余盒饭数量(分别设置线程名称 窗口一,窗口二).
                    • 4.2.7 同时开启两个线程(并且设置线程名称),共同输出1-10之间的所有数字,并且将输出偶数的线程名称打印出来。
                相关产品与服务
                容器服务
                腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档