Java多线程(二)

本文承接上一篇文章《Java多线程(一)》

四.Java多线程的阻塞状态与线程控制

上文已经提到Java阻塞的几种具体类型。下面分别看下引起Java线程阻塞的主要方法。

1.join()

join —— 让一个线程等待另一个线程完成才继续执行。如A线程线程执行体中调用B线程的join()方法,则A线程被阻塞,知道B线程执行完为止,A才能得以继续执行。

 1 public class ThreadTest {
 2
 3     public static void main(String[] args) {
 4
 5         MyRunnable myRunnable = new MyRunnable();
 6         Thread thread = new Thread(myRunnable);
 7
 8         for (int i = 0; i < 100; i++) {
 9             System.out.println(Thread.currentThread().getName() + " " + i);
10             if (i == 30) {
11                 thread.start();
12                 try {
13                     thread.join();    // main线程需要等待thread线程执行完后才能继续执行
14                 } catch (InterruptedException e) {
15                     e.printStackTrace();
16                 }
17             }
18         }
19     }
20 }
21
22 class MyRunnable implements Runnable {
23
24     @Override
25     public void run() {
26         for (int i = 0; i < 100; i++) {
27             System.out.println(Thread.currentThread().getName() + " " + i);
28         }
29     }
30 }

2.sleep()

sleep —— 让当前的正在执行的线程暂停指定的时间,并进入阻塞状态。在其睡眠的时间段内,该线程由于不是处于就绪状态,因此不会得到执行的机会。即使此时系统中没有任何其他可执行的线程,出于sleep()中的线程也不会执行。因此sleep()方法常用来暂停线程执行。

前面有讲到,当调用了新建的线程的start()方法后,线程进入到就绪状态,可能会在接下来的某个时间获取CPU时间片得以执行,如果希望这个新线程必然性的立即执行,直接调用原来线程的sleep(1)即可。

 1 public class ThreadTest {
 2
 3     public static void main(String[] args) {
 4
 5         MyRunnable myRunnable = new MyRunnable();
 6         Thread thread = new Thread(myRunnable);
 7
 8         for (int i = 0; i < 100; i++) {
 9             System.out.println(Thread.currentThread().getName() + " " + i);
10             if (i == 30) {
11                 thread.start();
12                 try {
13                     Thread.sleep(1);   // 使得thread必然能够马上得以执行
14                 } catch (InterruptedException e) {
15                     e.printStackTrace();
16                 }
17             }
18         }
19     }
20 }
21
22 class MyRunnable implements Runnable {
23
24     @Override
25     public void run() {
26         for (int i = 0; i < 100; i++) {
27             System.out.println(Thread.currentThread().getName() + " " + i);
28         }
29     }
30 }

注:睡一个毫秒级够了,因为CPU不会空闲,会切换到新建的线程。

3.后台线程(Daemon Thread)

概念/目的:后台线程主要是为其他线程(相对可以称之为前台线程)提供服务,或“守护线程”。如JVM中的垃圾回收线程。

生命周期:后台线程的生命周期与前台线程生命周期有一定关联。主要体现在:当所有的前台线程都进入死亡状态时,后台线程会自动死亡(其实这个也很好理解,因为后台线程存在的目的在于为前台线程服务的,既然所有的前台线程都死亡了,那它自己还留着有什么用...伟大啊 ! !)。

设置后台线程:调用Thread对象的setDaemon(true)方法可以将指定的线程设置为后台线程。

 1 public class ThreadTest {
 2
 3     public static void main(String[] args) {
 4         Thread myThread = new MyThread();
 5         for (int i = 0; i < 100; i++) {
 6             System.out.println("main thread i = " + i);
 7             if (i == 20) {
 8                 myThread.setDaemon(true);
 9                 myThread.start();
10             }
11         }
12     }
13
14 }
15
16 class MyThread extends Thread {
17
18     public void run() {
19         for (int i = 0; i < 100; i++) {
20             System.out.println("i = " + i);
21             try {
22                 Thread.sleep(1);
23             } catch (InterruptedException e) {
24                 // TODO Auto-generated catch block
25                 e.printStackTrace();
26             }
27         }
28     }
29 }

判断线程是否是后台线程:调用thread对象的isDeamon()方法。

注:main线程默认是前台线程,前台线程创建中创建的子线程默认是前台线程,后台线程中创建的线程默认是后台线程。调用setDeamon(true)方法将前台线程设置为后台线程时,需要在start()方法调用之前。前天线程都死亡后,JVM通知后台线程死亡,但从接收指令到作出响应,需要一定的时间。

4.改变线程的优先级/setPriority():

每个线程在执行时都具有一定的优先级,优先级高的线程具有较多的执行机会。每个线程默认的优先级都与创建它的线程的优先级相同。main线程默认具有普通优先级。

设置线程优先级:setPriority(int priorityLevel)。参数priorityLevel范围在1-10之间,常用的有如下三个静态常量值:

MAX_PRIORITY:10

MIN_PRIORITY:1

NORM_PRIORITY:5

获取线程优先级:getPriority()。

注:具有较高线程优先级的线程对象仅表示此线程具有较多的执行机会,而非优先执行。

 1 public class ThreadTest {
 2
 3     public static void main(String[] args) {
 4         Thread myThread = new MyThread();
 5         for (int i = 0; i < 100; i++) {
 6             System.out.println("main thread i = " + i);
 7             if (i == 20) {
 8                 myThread.setPriority(Thread.MAX_PRIORITY);
 9                 myThread.start();
10             }
11         }
12     }
13
14 }
15
16 class MyThread extends Thread {
17
18     public void run() {
19         for (int i = 0; i < 100; i++) {
20             System.out.println("i = " + i);
21         }
22     }
23 }

5.线程让步:yield()

上一篇博文中已经讲到了yield()的基本作用,同时,yield()方法还与线程优先级有关,当某个线程调用yiled()方法从运行状态转换到就绪状态后,CPU从就绪状态线程队列中只会选择与该线程优先级相同或优先级更高的线程去执行。

 1 public class ThreadTest {
 2
 3     public static void main(String[] args) {
 4         Thread myThread1 = new MyThread1();
 5         Thread myThread2 = new MyThread2();
 6         myThread1.setPriority(Thread.MAX_PRIORITY);
 7         myThread2.setPriority(Thread.MIN_PRIORITY);
 8         for (int i = 0; i < 100; i++) {
 9             System.out.println("main thread i = " + i);
10             if (i == 20) {
11                 myThread1.start();
12                 myThread2.start();
13                 Thread.yield();
14             }
15         }
16     }
17
18 }
19
20 class MyThread1 extends Thread {
21
22     public void run() {
23         for (int i = 0; i < 100; i++) {
24             System.out.println("myThread 1 --  i = " + i);
25         }
26     }
27 }
28
29 class MyThread2 extends Thread {
30
31     public void run() {
32         for (int i = 0; i < 100; i++) {
33             System.out.println("myThread 2 --  i = " + i);
34         }
35     }
36 }

时间: 2025-01-04 23:22:45

Java多线程(二)的相关文章

java多线程(二)——用到的设计模式

接上篇:java多线程(一)http://www.cnblogs.com/ChaosJu/p/4528895.html java实现多线程的方式二,实现Runable接口用到设计模式——静态代理模式 一.代理模式 代理模式的定义 代理模式(Proxy Pattern)是对象的结构型模式,代理模式给某一个对象提供了一个代理对象,并由代理对象控制对原对象的引用. 代理模式不会改变原来的接口和行为,只是转由代理干某件事,代理可以控制原来的目标,例如:代理商,代理商只会卖东西,但并不会改变行为,不会制造

从零开始学习Java多线程(二)

前面已经简单介绍进程和线程,为后续学习做铺垫.本文讨论多线程传参,Java多线程异常处理机制. 1. 多线程的参数传递 在传统开发过程中,我们习惯在调用函数时,将所需的参数传入其中,通过函数内部逻辑处理返回结果,大多情况下,整个过程均是由一条线程执行,排除运行不必要的的偶发性,似乎并不会出现意料之外的结果.而在多线程环境下,在使用线程时需要对线程进行一些必要的初始化,线程对这些数据进行处理后返回结果,由于线程的运行和结束并不可控,线程传参变得复杂起来,本文就以上问题介绍三种常用的传递参数方式.

Java多线程(二) 多线程的锁机制

当两条线程同时访问一个类的时候,可能会带来一些问题.并发线程重入可能会带来内存泄漏.程序不可控等等.不管是线程间的通讯还是线程共享数据都需要使用Java的锁机制控制并发代码产生的问题.本篇总结主要著名Java的锁机制,阐述多线程下如何使用锁机制进行并发线程沟通. 1.并发下的程序异常 先看下下面两个代码,查看异常内容. 异常1:单例模式 1 package com.scl.thread; 2 3 public class SingletonException 4 { 5 public stati

java多线程二之线程同步的三种方法

java多线程的难点是在:处理多个线程同步与并发运行时线程间的通信问题.java在处理线程同步时,常用方法有: 1.synchronized关键字. 2.Lock显示加锁. 3.信号量Semaphore. 线程同步问题引入: 创建一个银行账户Account类,在创建并启动100个线程往同一个Account类实例里面添加一块钱.在没有使用上面三种方法的情况下: 代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

Java多线程——&lt;二&gt;将任务交给线程,线程声明及启动

一.任务和线程 <thinking in java>中专门有一小节中对线程和任务两个概念进行了具体的区分,这也恰好说明任务和线程是有区别的. 正如前文所提到的,任务只是一段代码,一段要达成你目的的代码,这段代码写在哪,怎么写其实无所谓,只是因为你希望java的多线程机制能够识别并调用你编写的任务,所以规定了Runnable接口,让你的任务来实现该接口,把你想做的工作在实现该接口的run方法中实现. 那么,已经定义了任务类,那任务和线程有什么关系呢? java的线程是用来驱动任务执行的,也就是说

java多线程(二)——锁机制synchronized(同步方法)

synchronized Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码.当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一个时间内只能有一个线程得到执行.另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块.然而,当一个线程访问object的一个加锁代码块时,另一个线程仍然可以访问该object中的非加锁代码块. ——以上来源百度百科 一.方法内的变量为线程安全 “非线程安全”的问题

java多线程(二)

一.ThreadLocal:线程局部变量,是一种多线程间并发访问变量的解决方案.与其synchronized等枷锁的方式不同,ThreadLocal完全不提供锁,而是以空间换时间的手段,为每个线程提供变量的独立副本,以保障线程安全.从性能上说,ThreadLocal不具备绝对的优势,在并发不是很高的时候,枷锁的性能会更好,但作为一套与锁完全无关的线程解决方案,在高并发量或者竞争激烈的场景,使用ThreadLocal可以在一定程度上减少锁竞争. 二.并发类容器介绍 ConcurrentHashMa

Java 多线程(二)之 Thread 优先级

Thread 中线程优先级相关属性 每个线程均有优先级,在 Thread 中, 与优先级对应的属性如下: /** * 线程的优先级属性 */ private int priority; /** * 线程所能拥有的最大优先级. */ public final static int MIN_PRIORITY = 1; /** * 线程默认的优先级. */ public final static int NORM_PRIORITY = 5; /** * 线程所能拥有的最大优先级. */ public

Java多线程 二 线程间通信

线程间通信: 多个线程在处理同一资源,但是 等待唤醒机制 涉及的方法: 1.wait() 让线程处于冻结状态,被wait的线程会被存储到线程池中. 2.notify() 唤醒线程池中的一个线程(任意) 3.notifyAll() 唤醒线程池中的所有线程.. 这些方法都必须定义在同步中, 因为这些方法是用于操作线程状态的方法. 必须明确到底操作的那个锁上的线程. 为什么操作线程的方法wait notify notifyAll定义在了Object中. 因为这些方法是监视器方法,监视器其实就是锁. 锁

Java多线程(五) Lock接口,ReentranctLock,ReentrantReadWriteLock

在JDK5里面,提供了一个Lock接口.该接口通过底层框架的形式为设计更面向对象.可更加细粒度控制线程代码.更灵活控制线程通信提供了基础.实现Lock接口且使用得比较多的是可重入锁(ReentrantLock)以及读写锁(ReentrantReadWriteLock). 1. ReentrantLock 在Java多线程(二) 多线程的锁机制 里面,已经总结过通过使用Synchronized关键字实现线程内的方法锁定.但使用Synchronized关键字有一些局限性,上锁和释放锁是由JVM决定的