这里仅仅是我读该书收获的知识点,如果我熟悉的我自动或略不写
一、创建方式
java多线程有两种创建方式
- 继承thread
- 实现Runnable接口
下面演示实现Runnable接口的创建方式:
Class A implements Runable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":运行了");
}
}
public static void main(String[] args) {
A a = new A();
Thread thread = new Thread(a);
thread.start();
}
Thread的构造方法中,传递的是Runnable类型,public Thread(Runnable target),而且Thread也是实现Runnable 接口的,所以如果一个类继承了Thread,然后又通过Thread的构造函数传递给new Thread()也是可行的。比如下面的例子:
Class A implements Thread{
public void run() {
System.out.println(Thread.currentThread().getName()+":运行了");
}
}
public static void main(String[] args) {
A a = new A(); //Thread-0
Thread thread = new Thread(a);//Thread-1
thread .start();
}
但是通过这种方式,实际上创建了2个线程,第一个就是继承Thread线程,可以通过a.start直接运行,第二个线程就是thread变量代表的线程。下面通过isAlive方法来打印来进一步说明
static class A extends Thread{
@Override
public void run() {
System.out.println("Thread.currentThread().getName:"+Thread.currentThread().getName());
System.out.println("this.getName:"+this.getName());
System.out.println("Thread.currentThread():"+Thread.currentThread().isAlive());
System.out.println("this.isActive:"+this.isAlive());
}
}
public static void main(String[] args) {
A a = new A();
Thread t = new Thread(a);
t.start();
}
可知Thread.currentThread()代表了线程1.
this代表了线程0
因为调用的是t.start();所以Thread.currentThread().isAlive()方法返回时true,而this.isAlive()代表线程0返回false
1.1、start和run
调用start方法后通知线程规划器,线程已经准备完毕,等待CPU调度,然后调用对象的run方法。
如果直接调用run方法,根本就没有开启一个线程,而是main线程调用了对象的run方法。
二、线程停止
这部分目前是不完整的,后期会补充
- 退出标志,正常退出
- interrupte方法
- stop
2.1 interrupt方法
不是静态方法,所以他针对的是调用该方法的对象
/**
* Interrupts this thread.
*/
紧紧是在线程中打了一个停止标记,开发者,可以利用这个停止标记通过抛出异常或者return来停止这个线程。
判断线程中断标志的两个方法
interrupted:
官方解释
/**
* Tests whether the current thread has been interrupted. The
* interrupted status of the thread is cleared by this method.
*/
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
测试当前线程是否被中断,并且清除中断状态。他是个静态方法,所以和调用者无关,他关系的是当前对象是否中断。
isInterrupted:
/**
* Tests whether this thread has been interrupted. The interrupted
* status of the thread is unaffected by this method.
*/
public boolean isInterrupted() {
return isInterrupted(false);
}
注意他是个非静态方法,所以他是让调用者线程中断,并且不清除中断标志。
下面演示一个经典的通过中断标志来停止线程的
public static void main(String[] args) {
try {
B b = new B();
b.start();
Thread.sleep(1000);
b.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static class B extends Thread{
@Override
public void run() {
super.run();
try {
for(int i=0;i<500000;i++){
if(this.isInterrupted()){
System.out.println("线程"+this.getName()+"已经结束");
throw new InterruptedException();
}
System.out.println("i="+i);
}
System.out.println("for之外的语句");
} catch (Exception e) {
e.printStackTrace();
}
}
}
注意sleep+interrupt方法。
/**
* Causes the currently executing thread to sleep (temporarily cease
* execution) for the specified number of milliseconds, subject to
* the precision and accuracy of system timers and schedulers. The thread
* does not lose ownership of any monitors.
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* interrupted status of the current thread is
* cleared when this exception is thrown.
*/
public static native void sleep(long millis) throws InterruptedException;
注意sleep方法会抛出InterruptedException异常,也就是说如果一个线程被打了中断标志,然后执行sleep就会包这个异常。
2.2 stop
这个方法比较暴力。
/*
* @deprecated This method is inherently unsafe. Stopping a thread with
* Thread.stop causes it to unlock all of the monitors that it
* has locked (as a natural consequence of the unchecked
*ThreadDeath
exception propagating up the stack). If
* any of the objects previously protected by these monitors were in
* an inconsistent state, the damaged objects become visible to
* other threads, potentially resulting in arbitrary behavior. Many
* uses ofstop
should be replaced by code that simply
* modifies some variable to indicate that the target thread should
* stop running. The target thread should check this variable
* regularly, and return from its run method in an orderly fashion
* if the variable indicates that it is to stop running. If the
* target thread waits for long periods (on a condition variable,
* for example), theinterrupt
method should be used to
* interrupt the wait.
*/
@Deprecated
public final void stop()
从官方解释中可可以看到这个方法已经被弃用,首先他会突然释放它多有的锁,这样就会导致前后不一致(inconsistent).他们也推荐使用中断标志来结束。
//共享数据
public class ShareData extends Thread{
String username = "a";
String password = "aa";
public void print(String username,String password){
this.username = username;
Thread.sleep(2000);
this.password = password;
}
}
//一个简单的线程
public class A extends Thread{
private ShareData shareData;
public A(ShareData shareData){
this.shareData = shareData;
}
@Override
public void run() {
shareData.print("b","bb");
}
}
//主线程
public static void main(String[] args) {
try {
ShareData shareData = new ShareData();
A thread = new A(shareData );
thread .start();
Thread.sleep(1000);
thread stop();
sout(shareData);//此时会打印b,aa(数据已经出现不一致了)
} catch (InterruptedException e) {
e.printStackTrace();
}
}
三、线程暂停
suspend和resumed,注意这两个方法也已经丢弃,但是了解丢弃的意义还是很有用的。
/**
* Suspends this thread.
* If the thread is alive, it is suspended and makes no further
* progress unless and until it is resumed.
* @deprecated This method has been deprecated, as it is
* inherently deadlock-prone. If the target thread holds a lock on the
* monitor protecting a critical system resource when it is suspended, no
* thread can access this resource until the target thread is resumed. If
* the thread that would resume the target thread attempts to lock this
* monitor prior to callingresume
, deadlock results. Such
* deadlocks typically manifest themselves as “frozen” processes.
*/
@Deprecated
public final void suspend() {
checkAccess();
suspend0();
}
我认为官方这个解释已经够完美,书中说缺点–不同步其实基本不会出现。
inherently deadlock:天然的死锁情况
主要原因还是他不会释放它拥有的锁,比如执行suspend需要锁A,执行该方法后,他会一直暂停,指导调用resumed方法,如果调用resumed方法也需要锁A,那么就会无限死锁。
四、线程优先级
其实这个在大学学习操作系统的时候,讲的很清楚。
**优先级具有随机性:**线程的优先级也有规则性,那就是CPU尽量将执行资源让给优先级高的线程。这个尽量就体现了随机性。
四、守护线程
以前对守护线程理解有误。
守护线程其实就是个辅助角色,如果被辅助的不存在了,那么它就会消失。
public static void main(String[] args) {
try {
A a = new A();
A aa = new A();
a.setDaemon(true);
a.start();
Thread.sleep(4000);
System.out.println("main end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static class A extends Thread{
int i;
@Override
public void run() {
super.run();
while(true){
i++;
System.out.println("i="+i);
}
}
}
因为a是守护线程,所以随着主线程main结束,他也就结束了。