1.线程的基本操作
线程共有5个状态:
NEW(新建状态)
RUNNABLE(可运行态)
TERMINATED(线程终止)
BLOCKED (阻塞) ,进入同步块时申请监视器导致的阻塞
WAITING (无限等待)
TIMED_WAITING(有限等待)
1.1新建线程
常见有两种创建线程的方法:
1)继承Thread类重写run()方法。
2)继承Runnable接口。在构造时传入具体实现对象。
如果没有传递target实例,那么run方法内部就不会执行任何逻辑。
如果传递了tartget,那么run方法便会执行target实例中的run方法。
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
.....
/* What will be run. */
private Runnable target;
@Override
public void run() {
if (target != null) {
target.run();
}
}
要注意的是,如果没有执行start()方法开启线程,而是直接在主线程中调用一个线程的run()方法,结果只会在当前线程调用run()方法,而并没有实质性地开启新线程。
1.2 终止线程——stop()
Thread.stop()是一个被弃用的方法。主要原因是线程的突然终止会导致数据的不一致。太过于粗暴。
@Deprecated
public final void stop() {
....
}
1.3 中断线程——interrupt()
public void Thread.interrupt() //中断线程
public boolean Thread.isInterrupted() //判断是否被中断
public static boolean Thread.interrupted() //判断是否被中断,并清除当前中断状态
public void run(){
while(true){
//doSomething.....
}
}
t1.interrupt(); //发出中断命令,而并未做出响应。所以while循环会继续执行下去
/////////////////////////////////////////////////////////////////////////////////
public void run(){
while(true){
if(Thread.currentThread.isInterrupted()){
System.out.println("Interruted!");
break;
}
//doSomething...
}
}
t1.interrupt(); //发出中断命令,while循环中会判断出现中断,退出循环
////////////////////////////////////////////////////////////////////////////
但若是doSomething中出现异常时候,要防范抛出异常时,中断标记位会被清空。要重新中断
public void run(){
while(true){
if(Thread.currentThread.isInterrupted()){
System.out.println("Interruted!");
break;
}
try{
Thread.sleep(2000);
}catch(InterruptedException e){
System.out.println("Interrupted When Sleep");
//由于抛出异常后会清除中断标记,所以再次设置中断标记,以被if检测到
Thread.currentThread().interrupt()
}
//doSomething...
}
}
1.4 挂起(suspend) 和继续执行(resume) 线程
这两个操作也是不被推荐使用的。两个线程无法控制顺序时,当resume()在suspend()执行之前就已经执行,所以此后被挂起的线程便再也不能被唤醒了,而suspend()是不会释放锁的,导致等待在这个锁上的其他线程会持续等待下去。
1.5 等待线程结束(join)和谦让(yeild)
join() 表示等待前一个线程执行完毕后再执行,也有叫“线程插队”
public class JoinMain{
public volatile static int i = 0;
public static class AddThread extends Thread{
@Override
public void run() {
for(i=0; i < 10000000; i++);
}
}
public static void main(String args[]) throws InterruptedException{
AddThread at = new AddThread();
at.start();
at.join(); //主线程会等待at线程执行完毕后再一起走
System.out.println(i);
}
}
/////////////////////////////////////////////////
join的本质:
while(isAlive()){
wait(0);
}
线程执行完毕会调用notifyAll()通知等待的所有线程
yeild会让出时间片,但不是白给,而是再和别的线程竞争。”再给对方一次竞争机会“。
public final void join() throws InterruptedException
public final synchronized void join(long millis) throws InterruptedException//一般用于测试目的
2. 守护线程&线程优先级
当一个Java应用内,只有守护线程时,JVM就会自然退出。
java 中的线程优先级的范围是1~10,默认的优先级是5。高优先级的线程更容易在竞争中获胜。
package Thread;
/**
* 后台线程
* @author liq
*
*/
public class DamonThread {
class Damon implements Runnable{
@Override
public void run() {
while(true) {
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+" is running");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
Damon damon = new DamonThread().new Damon();
Thread damonThread = new Thread(damon, "后台线程");
damonThread.setPriority(10); //在start之前设置优先级
damonThread.setDaemon(true);
System.out.println("'damonThread' is a Damon Thread?"+damonThread.isDaemon());
damonThread.start();
for(int i=0; i<10; i++) {
try {
Thread.sleep(1000);
System.out.println("Main Thrad is Running"+i);
if (i == 9) {
System.out.println("Main Thrad is dead");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3. 基本的线程同步操作——synchronized关键字&wait(),notify()
3.1 synchronized线程同步
-指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁。
-直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。
-直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。
下面进行
/**
* synchronized代码块
* @author liq
*
*/
public class SynchronizedBlock {
public static void main(String[] args) {
Ticket ticketTask = new Ticket();
new Thread(ticketTask,"售票窗口1").start();
new Thread(ticketTask,"售票窗口2").start();
new Thread(ticketTask,"售票窗口3").start();
new Thread(ticketTask,"售票窗口4").start();
}
}
class Ticket implements Runnable{
private int ticketsNum = 10; //总共十张票
Object lock = new Object();
@Override
public void run() {
while(true) {
synchronized (lock) {
try {
if (ticketsNum > 0) {
System.out.println(Thread.currentThread().getName()+"售票,现存:"+ --ticketsNum);
Thread.sleep(1000);
}else {
System.out.println("票售完了!");
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
锁静态方法,就是对当前类加锁
class Ticket implements Runnable{
private static int ticketsNum = 10; //总共十张票
Object lock = new Object();
@Override
public void run() {
sellTickt();
}
public static synchronized void sellTickt() { //锁静态方法,就是对当前类加锁
while(true) {
try {
if (ticketsNum > 0) {
System.out.println(Thread.currentThread().getName()+"售票,现存:"+ --ticketsNum);
Thread.sleep(1000);
}else {
System.out.println("票售完了!");
break;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3.2 wait()和notify()实现线程同步
需要注意:
1)wait和notify方法必须在同步代码块中执行,即在执行前需要拿到锁。
2)wait()会释放锁。
3)notify也会释放锁。
notify()是在同步队列中随机唤醒一个线程
notifyAll()是唤醒全部开始竞争锁。
实现生产者消费者例子:
/**
* This demon shows the co-operation between two threads of Input and Output
* @author liq
*
*/
public class WaitAndNotify {
public static void main(String[] args) {
Storage storage = new Storage();
Input input = new Input(storage);
Output output = new Output(storage);
new Thread(input,"input线程").start();
new Thread(output,"output线程").start();
}
}
//this is Input thread which is used to play a producer role to put a number in storage per second
class Input implements Runnable{
Storage storage;
int num;
public Input(Storage storage) {
this.storage = storage;
}
@Override
public void run() {
while(true) {
try {
Thread.sleep(1000);
storage.put(num++);
System.out.println("producer puts num:"+num);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//this is Output thread which is used to play a consumer role to get a number in storage per second
class Output implements Runnable{
Storage storage;
public Output(Storage storage) {
this.storage = storage;
}
@Override
public void run() {
while(true) {
try {
Thread.sleep(1000);
System.out.println("------------------------consumer gets num:"+storage.get());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//this is a mutual storage of consumer and producer thread to storage number
class Storage{
private int[] cells = new int[10];
int size = 0; //实际存储容量
int inPos,outPos;
//往cells中放入一个数
public synchronized void put(int in) {
try {
if (size == 10) { //若存储已满,当前线程等待
this.wait();
}
cells[inPos++] = in;
size++;
//超过10位置重新从0开始存放
if (inPos == 10) {
inPos=0;
}
this.notifyAll(); //通知在此同步锁上等待的其他线程(消费者)开始执行
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//从cells中取出一个数
public synchronized int get() {
int result = 0;
try {
//Storage 为空了,线程等待
if (size == 0) {
this.wait(); //若存储已空,当前线程等待。
}
result = cells[outPos++];
size--;
//超过大小,从0开始取出
if (outPos == 10) {
outPos = 0;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return result;
}
}