关于多线程

基本概念不多做介绍。

线程创建

两种方法:

1
2
3
4
5
6
7
8
9
public class MyThread extends Thread{
@Override
public void run() {
//TODO
}
}
----------------------------------------
MyThread t1 = new MyThread("线程1");
MyThread t2 = new MyThread("线程2");
1
2
3
4
5
6
7
8
9
10
public class MyRunnable implements Runnable{
@Override
public void run() {
//TODO
}
}
----------------------------------------
MyRunnable t = new MyRunnable();
Thread t1 = new Thread(t,"线程1");
Thread t2 = new Thread(t,"线程2");

可以看出最明显的区别是上者多线程需要创建多个对象,而下者可以使用一个对象,这样就可以在MyRunnable中定义数据,多个线程共享,再者,java”单继承,多实现”,故下者还可以继承其他类进行扩展,所以下者用的多一些。

线程守护

可以把线程守护理解为保镖,用它去保护其他线程,若其他线程结束或者中断,那它也没有存在的意义,会被强制终止。

1
t2.setDaemon(true); //设置t2为守护线程

线程中断

线程中断需要使用

1
t1.interrupt();

但是需要注意的是此时并没有真正的中断该线程,只是将这个线程的中断状态的布尔值进行了修改,要想真正中断

1
2
3
4
if(interrupted()) {//若当前线程被设置为中断状态
// System.out.println("释放资源");
break;
}

也就是中断前给线程一个留“临终遗言”的机会,交代完“后事”才可以真正被中断。

直接杀死线程的stop方法已经被弃用。

线程生命周期

https://blog.csdn.net/lonelyroamer/article/details/7949969

线程安全

什么是线程安全:多个线程同时要修改一个变量的时候,引起冲突
线程安全问题解决

  • 1
    2
    3
    synchronized(对象){//锁住某个对象,如果这个对象已经被锁定,那么等待。
    //TODO
    }//执行完之后,归还钥匙
    1
    2
    3
    4
    5
    6
    7
    8
    9
    private ReentrantLock lock = new ReentrantLock();
    ………………
    lock.lock();//加锁
    try {
    //TODO
    }
    } finally {
    lock.unlock();
    }
  • 出现线程安全问题的地方,要锁同一个对象(可以是当前对象,也可以单独创建一个对象)

  • 锁住某个对象,如果这个对象已经被锁定,那么停止当前线程的执行,一直等待,一直等到对象被解锁。

    (保证同一个时间,只有一个线程在使用这个对象)
  • 创建同步方法

    同步方法锁的是哪个对象呢?锁定的是当前对象this

另补充:线程安全的类

  • 安全: StringBuffer Vector
  • 不安全:StringBuilder ArrayList

死锁问题

死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。

形象化例子:吃饭需要同时使用刀叉,一个人拿叉等刀,另一个人拿刀等叉。

产生举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Thread1 implements Runnable{
@Override
public void run() {
synchronized (Demo07_DeadLock.lock1) {
System.out.println("取得第一把锁之后要做的事情");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (Demo07_DeadLock.lock2) {
System.out.println("Thread1同时取得两把锁之后要做的事情");
}
}
}
}

class Thread2 implements Runnable{
@Override
public void run() {
synchronized (Demo07_DeadLock.lock2) {
System.out.println("取得第二把锁之后要做的事情");
synchronized (Demo07_DeadLock.lock1) {
System.out.println("Thread2同时取得两把锁之后要做的事情");
}
}
}
}

这样两个进程都卡住等待

1
2
3
输出:
取得第一把锁之后要做的事情
取得第二把锁之后要做的事情

解决方案:将两个线程取锁的顺序换为一样

1
2
3
4
5
6
7
8
9
10
11
class Thread2 implements Runnable{
@Override
public void run() {
synchronized (Demo07_DeadLock.lock1) {
synchronized (Demo07_DeadLock.lock2) {
System.out.println("取得第二把锁之后要做的事情");
System.out.println("Thread2同时取得两把锁之后要做的事情");
}
}
}
}

线程组

线程组ThreadGroup 默认处于同一个组里面
使用线程组可以统一设置这个组内线程的一些东西。比如设置优先级,设置是否是守护线程。

1
2
3
4
MyRunnable r = new MyRunnable();
ThreadGroup tg = new ThreadGroup("我们的线程组");
Thread t1 = new Thread(tg,r);
Thread t2 = new Thread(tg,r);

定时器

作用:一种工具,线程用其安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行。
使用类:Timer(定时器)和TimerTask(定时器启动之后要执行的任务)

timer.schedule(TimerTask task, long delay) 
timer.schedule(TimerTask task, long delay, long period) 
timer.schedule(TimerTask task, Date time) 
timer.cancel();

:转载文章请注明出处,谢谢~