您的位置:首页 > 其它

从关键字学多线程

2015-06-11 17:30 260 查看
一、多线程相关关键字

Runnable、Thread:线程的父类,区别就是使用Runnable接口不可以使用Thread的相关的特性,如sleep等;

run:线程类中必须存在的方法;

start:启动一个线程,经常被面试的人提到,我很郁闷;

synchronized:同步锁,指定不同的对象,锁的内容不同,如一把锁可以锁门,也可以锁窗户;

wait:先休息休息,好了的时候再叫我,但别忘了先锁门哦;

notify:让一个等待的线程活动起来,效率高点;

notifyAll:让所有等待的线程都起来抢东西了,但我更安全;

sleep:先休息休息,一会儿自己醒来,除非你不让我休息了;

interrupt:休息这以久还没有等到,不等了,但是不是中断这个线程;

setDaemon:守护线程,请不要在乎我的存在,我是为主人服务的;

join:等等,好了再继续;

yield:不释放锁的等待,尽可能把优先级交给其它线程,不可以放到synchronized锁定中;

ThreadLocal:多线程我也不怕共享资源。

Volatile:参看Java 理论与实践: 正确使用 Volatile 变量

二、实例

1、我是一个线程,展示一个简单的线程是怎么样练成的:

[java] view
plaincopy

public class IamThread extends Thread {

public void run(){

System.out.println("I am a thread");

}

}

或者

public class IamThread implements Runnable {

public void run(){

System.out.println("I am a thread");

}

}

启动线程:

new Thread(new IamThread()).start()

2、休息休息再说,这个是对sleep的简单使用,休息指定的时间后再工作,这里的时间设的长,是因为3要使用到它:

[java] view
plaincopy

public class IamThread extends Thread {

public void run() {

int i = 0;

while (true) {

try {

sleep(1000000000);

} catch (InterruptedException e) {

}

System.out.println(i++);

}

}

}

3、睡醒了吧,懒虫,不要一直让他沉睡,过2秒钟醒他一下,“工作”后,再继续睡,然后再过2秒钟再弄醒一下...如些循环,这里需要注意一下方法interrupt(),不要把这个理解为中断线程,理解为把当程线程唤醒更贴切:

[java] view
plaincopy

public class RunThread {

public static void main(String[] args) {

Thread thread = new Thread(new IamThread());

thread.start();

while (true) {

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

}

thread.interrupt();

}

}

}

4、饭好了叫我,对wait的使用示例,将线程放入到虚拟的wait set中,当对线程使用wait时,但是要想使用wait等待线程,需要注意两点,一是必须要获取锁定,如这里的synchroinzed关键字,二是必须要有notify()或notifyAll()方法来叫醒,否则线程会永远醒不过来:

[java] view
plaincopy

public class WaitThread extends Thread {

private boolean isReady = false;

public synchronized void eat(){

if(!isReady){

try {

wait();

} catch (InterruptedException e) {}

}

System.out.println("I eat happy!");

}

public synchronized void cook(){

isReady = true;

//notify();

notifyAll();

}

}

5、Join,全部好了再走,JOIN的使用情况是要获取到一个线程或者多个线程执行结果后,再继续执行下面的步骤,如果用采用JOIN,也许启动的线程还没有执行完毕,JVM就退出了;既然JVM可以等到线程执行完后再继续下面的步骤,我们可否使用JOIN来做分布式运算,这个你自己想哦:

[java] view
plaincopy

public class JoinThread extends Thread {

private static int n = 0;

public void run() {

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

try {

addN();

//sleep(3); // 为了使运行结果更随机,延迟3毫秒

} catch (Exception e) {}

}

private synchronized void addN() {n++;}

public static void main(String[] args) throws Exception {

Thread threads[] = new Thread[100];

for (int i = 0; i < threads.length; i++) {

threads[i] = new JoinThread();

}

for (int i = 0; i < threads.length; i++) {

threads[i].start();

}

// if (args.length > 0) {

for (int i = 0; i < threads.length; i++) {

// 100个线程都执行完后继续

threads[i].join();

}

// }

System.out.println("n=" + JoinThread.n);

}

}

注:以上的示例,并不是每次都会得到1000,这个我目前没有想明白是为什么,因为当上面执行到最后的输出的时候,启动的100个线程都已经执行完了,如果你有答案,请告诉我,我会非常感谢。

搞定及说明:正如热心的abbuggy所说的,synchronized是针对同一个对象的方法进行锁定的,而这里是针对一百个不同的对象,因而在这个示例中的addN方法中增加synchronized关键字,是一点意味都没有;这里我们需要关注的是这个变量n的线程安全性,并保证同一时刻只有一个线程对其进行增加操作,而变量n又恰恰是一个静态变量,而静态变量是并不属于某个特定对象,是被所有的对象所共享的,这个时候可以采用增加一个静态对象锁,这样就可以保证这个对象的安全性了,以上代码写成下面这样就没有问题了:

[java] view
plaincopy

public class JoinThread extends Thread {

private static int n = 0;

// 增加一个对象锁

private static Object o = new Object();

public void run() {

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

try {

addN();

// sleep(3); // 为了使运行结果更随机,延迟3毫秒

} catch (Exception e) {

}

}

private void addN() {

// 每次只允许一个线程访问这个变量

synchronized (o) {

n++;

}

}

public static void main(String[] args) throws Exception {

Thread threads[] = new Thread[100];

for (int i = 0; i < threads.length; i++) {

threads[i] = new JoinThread();

}

for (int i = 0; i < threads.length; i++) {

threads[i].start();

}

// if (args.length > 0) {

for (int i = 0; i < threads.length; i++) {

// 100个线程都执行完后继续

threads[i].join();

}

// }

System.out.println("n=" + JoinThread.n);

}

}

6、守护线程,JVM不需要依赖于守护线程是否执行完毕来确定是否退出,他的优先级很低,如垃圾收集集,待其它的线程需要执行时,袒护线程就会等其它线程执行,如果全部执行完了,虚拟机不会在意守护线程是否还有任务在执行,都会退出。简单的理解为守护线程为家仆,其它线程为主人,只需要看主人的脸色,而不会在科家仆的脸色,主人完了,那家仆完不完已经不重要了:

[java] view
plaincopy

public class RunDeamonThread {

public static void main(String[] args){

Thread doorKeeper = new Thread(new DoorKeeper());

doorKeeper.setDaemon(true);

doorKeeper.start();int i=0;

while(i<100){

Thread thread = new Thread(new IamThread());

thread.start();

i++;

}

}

}

class DoorKeeper extends Thread{

public void run(){

while(true){

System.out.println("I am a door guander,don't care me!");

}

}

}

7、ThreadLocal,用于在线程中传递变量

只有四个方法:

get() 返回此线程局部变量的当前线程副本中的值。

initialValue() 返回此线程局部变量的当前线程的“初始值”。只在get或set时执行一次

remove() 移除此线程局部变量当前线程的值。

set(T value) 将此线程局部变量的当前线程副本中的值设置为指定值。

[java] view
plaincopy

public class ThreadGlobalTest {

private static ThreadLocal<String> priviewStatus =

new ThreadLocal<String>();

public static String getPriviewStatus() {

return priviewStatus.get();

}

public static void setPriviewStatus(String status) {

priviewStatus.set(status);

}

}

8、yield,我一直等待,但是我也一直在工作,条件好了我就闪

[java] view
plaincopy

public class YieldTest {

private volatile boolean ready;

//注意此方法不可以加synchronized,因为yield是一种不会释放锁的等待

public void doSomething() {

while (!ready) {

Thread.yield();

}

}

public synchronized void setReady() {

ready = true;

}

}

三、一个巩固实例

这个实例是别人发到JAVAEYE上面的,我看的蛮有意思的,就贴在这里,

[java] view
plaincopy

public class Test {

public static void main(String[] args) {

MyClass1 myClass = new MyClass1();

new MyThread(myClass).start();

new MyThread1(myClass).start();

}

}

class MyClass1 {

public synchronized void m1() {

System.out.println("m1-1");

try {

this.wait(); // 暂停改当前线程,并且会释放锁

} catch (Exception e) {

e.printStackTrace();

}

System.out.println("m1-2");

try {

Thread.sleep(1000); // m1和m2同时暂停1秒钟

System.out.println("m1-3");

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("m1-4");

m2();

}

public synchronized void m2() {

System.out.println("m2-1");

this.notifyAll(); // 叫醒m1

System.out.println("m2-2");

try {

Thread.sleep(1000);

System.out.println("m2-3");

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("m2-4");

m1();

}

}

class MyThread extends Thread {

private MyClass1 myClass;

public MyThread(MyClass1 myClass){

this.myClass = myClass;

}

@Override

public void run() {

myClass.m1();

}

}

class MyThread1 extends Thread {

private MyClass1 myClass;

public MyThread1(MyClass1 myClass){

this.myClass = myClass;

}

@Override

public void run() {

try { // 暂停10毫秒是为了让m1先执行wait

Thread.sleep(10);

} catch (InterruptedException e1) {

e1.printStackTrace();

}

myClass.m2();

}

}

如果没有看明白,就去看这个贴子吧:

http://www.javaeye.com/topic/964712

有人褒,有人贬,看你怎么看了,最重要的是,学到东西才是最重要的

本文出自:冯立彬的博客
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: