进程线程的概念
进程是建立在操作系统的一次运行活动,是系统进行资源分配
和调度
的基本单位,可理解为一个一个的程序。线程是一次指令的顺序执行,是系统独立
和分配CPU
的基本单位,可理解为进程中独立运行的子任务。
为什么引入多线程
同步
单线程环境下,使得不相关、相互独立的任务之间需要排队等候CPU,使得CPU的利用率低下,异步
引入多线程使得不同的任务能在CPU自如地切换,提高了CPU的利用率。
线程实现方式
实现Runnable接口和继承Thread,并实现run()方法(一般使用Runnable接口实现,原因:接口能够实现多继承,类只能单继承)。
注
:在主函数中多次调用start()会出现Exception in thread "main" java.lang.IllegalThreadStateException
多线程环境下,在主函数直接调用Thread.run()方法而非调用Thread.start(),则实现的是同步效果,而非异步执行
线程方法

isAlive():测试线程是否处于活跃状态。
getId():线程的唯一标识号。
yield():放弃当前CPU让其他任务占用CPU,但放弃时间不确定。有可能刚放弃又占用。
sleep()/interrupt,wait()/notify notifyAll:
调用sleep()方法不会释放锁(不让出系统资源),而wait方法释放了锁(进入线程等待池等待,让出系统资源)使得其他线程可以使用同步控制块或者方法,其他线程可以占用CPU。一般wait不会加时间限制,因为如果wait线程的运行资源不够,再出来也没用,要等待其他线程调用notify/notifyAll唤醒等待池中的所有线程,才会进入就绪队列等待OS分配系统资源。sleep(milliseconds)可以用时间指定使它自动唤醒过来,如果时间不到只能调用interrupt()强行终止。
suspend/resume:
如果使用不当, 极易造成公共的同步对象的独占, 使得其他的线程无法访问公共的同步对象。
public class ThreadSuspendTest {
public synchronized void printString(){
System.out.println("begin");
if(Thread.currentThread().getName().equals("a")){
System.out.println("Thread a will suspend");
Thread.currentThread().suspend();
}
System.out.println("end");
}
public static void main(String[] args){
try{
final ThreadSuspendTest threadSuspendTest = new ThreadSuspendTest();
Thread thread1 = new Thread(new Runnable() {
public void run() {
threadSuspendTest.printString();
}
});
thread1.setName("a");
thread1.start();
Thread thread2 = new Thread(new Runnable() {
public void run() {
System.out.println("B线程启动了, 但是无法进入printString方法中");
System.out.println("因为printString()方法陪线程a锁定并且永远suspend暂停了");
threadSuspendTest.printString();
}
});
thread2.setName("B");
thread2.start();
}catch (Exception e){
e.printStackTrace();
}
}
}
/*begin
Thread a will suspend
B线程启动了, 但是无法进入printString方法中
因为printString()方法陪线程a锁定并且永远suspend暂停了*/
停止线程的方法

实例变量的安全问题
-
(1)实例变量
- (2)同一实例访问static时发生线程安全问题
- (3)system.out.println(i++);与i++/i--..联合使用异常
this.getName与currentThread().getName()区别
class CountOperate extends Thread {
public CountOperate() {
System.out.println("CountOperate---begin");
System.out.println("Thread.currentThread().getName()=" + Thread.currentThread().getName());
System.out.println("this.getName()=" + this.getName());
System.out.println("CountOperate---end");
}
@Override
public void run() {
System.out.println("run---begin");
System.out.println("Thread.currentThread().getName()=" + Thread.currentThread().getName());
System.out.println("this.getName()=" + this.getName());
System.out.println("run---end");
}
}
public class Run3_getName {
public static void main(String[] args) {
CountOperate c = new CountOperate();
Thread t1 = new Thread(c);
t1.setName("A");
t1.start();
}
}
输出:
CountOperate---begin
Thread.currentThread().getName()=main
this.getName()=Thread-0
CountOperate---end
run---begin
Thread.currentThread().getName()=A
this.getName()=Thread-0
run---end
守护线程

网友评论