Java多线程

线程的创建方法

Thread

从Thread类派生子类。

public class ThreadExample extends Thread {  
    public void run() {
        System.out.println("I am a example of Thread.");
    }
}
Runnable

从Runnable接口构造Thread对象。

public class RunnableExample extends Runnable {
    public void run() {
        System.out.println("I am a example of Runnable.");
    }
}

可以在Thread中添加方法,获取来自外部的变量,或者给构造方法添加参数来获取来自外部的变量,见如下代码。

public class ThreadExample extends Thread {
    private int varFromCreator;
    private int varFromMethod;
    //在构造方法中获取来自外部的变量
    public ThreadExample(String name, int a) {
            super(name);
            this.varFromCreator = a;
    }
    //在自定义方法中获取来自外部的变量
    public void addVar(int b) {
        this.varFromMethod = b;
    }
    public void run() {
        System.out.println("I am a example of Thread."+a);
    }
}


线程的调度

Thread.sleep(time)

让当前线程休眠一段时间,进入休眠的线程不会失去对现有monitor或锁的所有权。

time是一个整型值,单位为毫秒。

Thread.interrupt()

向线程发出中断信号,一般来说,线程收到中断信号时应该中断,直接终止。

但是线程收到其他线程发来的中断信号, 并不意味着一定要“停止”,线程正常运行期间, 即使接收到中断信号,也不理会,只有在sleep()时检测是否收到别人的中断信号,若是,则抛出异常并终止线程。

Thread.yield()

使用该方法,线程告知调度器:我可以放弃CPU的占用权,从而可能引起调度器唤醒其他线程。

Thread.stop()

不管当前线程的运行情况,强行终止线程,有可能引起各种不可预知的错误。所以,不要使用stop()!

Thread.join()

让当前线程保持执行,直到其执行结束。可以确定线程的执行顺序。


线程安全(Thread Safety)的四种策略

线程之间的“竞争条件”:作用于同一个mutable数据上的多个线程, 彼此之间存在对该数据的访问竞争并导致interleaving,导致postcondition可能被违反,这是不安全的。

线程安全:ADT或方法在多线程中要执行正确。

Confinement

将可变数据限制在单一线程内部,避免竞争。不允许任何线程直接读写该数据。

Immutability

使用不可变数据类型和不可变引用,避免多线程之间的race condition。不可变数据通常是线程安全的。

Using Threadsafe Data Types

如果必须要用mutable的数据类型在多线程之间共享数据,要使用线程安全的数据类型。

一般来说, JDK同时提供两个相同功能的类,一个是threadsafe,另一个不是。 原因:threadsafe的类一般性能上受影响。

Locks and Synchronization

前三种策略的核心思想:避免共享,即使共享,也只能读/不可写(immutable),即使可写 (mutable),共享的可写数据应自己具备在多线程之间协调的能力,即“使用线程安全的mutable ADT。

很多时候,我们并没有办法满足上述条件。

这里引入一种新机制:同步和锁。程序员来负责多线程之间对mutable数据的共享操作,通过“同步”策略,避免多线程同时访问数据。

synchronized(lock)代码块保证拥有lock的锁才能访问代码块中的内容,如果没有获得锁,则需要等待锁被释放。

lock可以是一个Object,也可以是自定义的一个对象。

class newLock {
    boolean condition = false;    //自定义对象可以通过内部定义一些变量,来影响线程的具体操作
}

public class Example extends Thread {
    private newLock lock = new newLock();
    private Object obj = new Object();
    public setLock(newLock lock) {
        this.lock = lock;
    }
    public void run() {
        ......
        synchronized(lock) {    //这个代码块只有获得lock锁的线程可以访问
            ......
            if(lock.condition) {   //这里,如果condition为true,就让这个线程进入阻塞状态,等待被唤醒
                try {              //可以用Object.notify()和Object.notifyAll()来唤醒
                    lock.wait(); 
                } catch(InterruptedException e) { 
                    e.printStackTrace(); 
                }
            }
        }
        synchronized(obj) {    //这个代码块只有获得obj锁的线程可以访问
            ......
        }
    }
}

同步机制会给性能带来极大影响,因为如果线程很多,有可能导致很多线程阻塞在一个位置等待获取锁,失去了多线程的意义,还有可能造成死锁。Java中很多mutable的类型都不是threadsafe就是这个原因。

除非必要,否则不要用synchronized,如果要用则尽可能减少lock的范围。

wait()、notify()、notifyAll()

注意,这三个方法是Object的方法,并不是Thread的方法。

Object.wait()让object所处的当前线程进入阻塞状态,直到其他线程调用该对象的notify()操作。

Object.notify()随机唤醒一个在该对象上调用wait()方法的线程。

Object.notifyAll()唤醒所有在该对象上调用wait()方法的线程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值