Fork me on GitHub

2019/6/19 线程介绍和创建

多线程介绍和创建

一 什么是线程

我的答案就是 启动一个jvm 就是启动了一个进程 然后操作系统就给进程分配内存空间, 然后jvm启动main方法,就是启动了一个main线程 然后就是在栈空间分配main线程的栈帧 就是进程的一条执行路径

简单理解就是liunx系统启动程序是以进程级别运行的, 进程是以线程为基本单位运行的, 粒度更细!

在jvm启动的时候 至少启动了一个main线程和一个gc线程 当然还有其他的一些线程

二 线程和进程的区别

  1. 调度

​ 进程是操作系统分配资源的一个基本单位。线程是 CPU调度的基本单位。

  1. 并发性

    一个进程里面可以有多个线程执行

  2. 独立性

    在同一进程中线程的独立性要比在不同的进程中独立性要低很多

  3. 系统开销

    线程切换的开销低于进程切换的开销

三 java thread api

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
A <i>thread</i> is a thread of execution in a program. The Java
* Virtual Machine allows an application to have multiple threads of
* execution running concurrently.

When a Java Virtual Machine starts up, there is usually a single
* non-daemon thread (which typically calls the method named
* <code>main</code> of some designated class). The Java Virtual
* Machine continues to execute threads until either of the following
* occurs:

创建线程的2种方法:
There are two ways to create a new thread of execution. One is to
* declare a class to be a subclass of <code>Thread</code>. This
* subclass should override the <code>run</code> method of class
* <code>Thread</code>. An instance of the subclass can then be
* allocated and started。

/**
* Causes this thread to begin execution; the Java Virtual Machine
* calls the <code>run</code> method of this thread.
* <p>
* The result is that two threads are running concurrently: the
* current thread (which returns from the call to the
* <code>start</code> method) and the other thread (which executes its
* <code>run</code> method).
* <p>
* It is never legal to start a thread more than once.
* In particular, a thread may not be restarted once it has completed
* execution.
*/
public synchronized void start()

public void run()

// thread 的构造函数
public Thread()
public Thread(Runnable target)
public Thread(Runnable target, AccessControlContext acc)
public Thread(ThreadGroup group, Runnable target)
public Thread(String name)
public Thread(ThreadGroup group, String name)
public Thread(Runnable target, String name)
public Thread(ThreadGroup group, Runnable target, String name)
// stackSize 线程栈内存的大小 这个是比较重要的参数
public Thread(ThreadGroup group, Runnable target, String name,long stackSize)

四 java创建线程

  1. 继承Thread

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class TryConcurrency {
    public static void main(String[] args){
    new Thread(() -> {
    while (true){
    System.out.println("我是" + Thread.currentThread());
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }).start();
    }
    }

    我是Thread[Thread-0,5,main]
    我是Thread[Thread-0,5,main]
    我是Thread[Thread-0,5,main]
  2. 实现Runable

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Runnable r = () -> {
    while (true){
    System.out.println("我是实现了Runnable: " + Thread.currentThread());
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    };
    new Thread(r).start();
  3. 使用Callable

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    Callable<Integer> c = () -> {
    int sum = 0;
    for (int i = 0; i <= 100000; i++) {
    sum += i;
    }
    return sum;
    };
    FutureTask<Integer> result = new FutureTask(c);
    new Thread(result).start();

    try {
    Integer o = result.get();
    System.out.println(o);
    } catch (InterruptedException e) {
    e.printStackTrace();
    } catch (ExecutionException e) {
    e.printStackTrace();
    }

    705082704
  4. 使用线程池

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //构造一个线程池
    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
    1,
    1,
    10,
    TimeUnit.SECONDS,
    new ArrayBlockingQueue<>(1),
    new ThreadPoolExecutor.DiscardOldestPolicy());

    threadPool.execute(() -> {
    try {
    while (true){
    System.out.println("----"+Thread.currentThread());
    Thread.sleep(1000);
    }
    } catch (Exception e) {
    e.printStackTrace();
    }finally{
    threadPool.shutdown();// 关闭线程池
    }
    });

四 线程的生命周期

  • 线程状态
    • new — new Thread()
    • runnable — start()
    • running
    • block
    • termate
  • 线程的start方法不能调用2次
  • start方法使用了模板设计模式 start - start0是本地方法 run方法其实就是一个模板方法 需要实现的方法

五 模拟银行排队叫号

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
public class TickWindow extends Thread{
private final String name;

public TickWindow(String name) {
this.name = name;
}
private static int MAX = 50;

// 加static 有问题 和 不加static 有线程安全问题
private static int index = 1;

@Override
public void run() {
while (index <= MAX){
System.out.println("当前柜台是: "+name+" 当前号码是: index " + index++);
}
}
}

public class Bank {
public static void main(String[] args) {
new TickWindow("一号柜台").start();
new TickWindow("二号柜台").start();
new TickWindow("三号柜台").start();
}
}

六 用runabble接口分离线程和业务逻辑

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
public class TestRunnable implements Runnable {
public static void main(String[] args) {
TestRunnable testRunnable = new TestRunnable();
new Thread(testRunnable).start();
new Thread(testRunnable).start();
new Thread(testRunnable).start();
}

private static final int MAX = 50;

//这里有一个线程安全的问题
private int index = 0;

@Override
public void run() {
while (index <= MAX){
System.out.println(Thread.currentThread().getName() + " hello ----> " + index++);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}


** 这种方式其实是使用了策略模式

七 Thread的api

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
1.  守护线程api t.setDaemon()

* Marks this thread as either a {@linkplain #isDaemon daemon} thread
* or a user thread. The Java Virtual Machine exits when the only
* threads running are all daemon threads.
*
* <p> This method must be invoked before the thread is started.
// 设置线程为守护线程
public final void setDaemon(boolean on)

public static void main(String[] args) {
Thread t = new Thread(()->{
try {
System.out.println(Thread.currentThread().getName() + "running");
Thread.sleep(10000);
System.out.println(Thread.currentThread().getName() + "Done");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 守护线程意思是 主线程死亡 守护线程不管是什么状态 也死亡

t.setDaemon(true); // 必须要在start()前面
t.start();

System.out.println(Thread.currentThread().getName());
}

2. 线程id t1.getId()
3. 线程名称 t1.getName()
4. 线程优先级 t1.setPriority(Thread.MAX_PRIORITY); 用处并不是很大
5. 线程状态 State getState()

6. 线程的join()方法
* Waits for this thread to die.
*
* <p> An invocation of this method behaves in exactly the same
* way as the invocation

public final void join()
public final synchronized void join(long millis, int nanos)
public final synchronized void join(long millis)

public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
IntStream.range(1, 1000).forEach(i->{
System.out.println(Thread.currentThread().getName() + " --> " + i);
});
});
t1.start();

//放到start之后

//先把t1 先执行完 再执行主线程 main线程等t1结束
t1.join();

IntStream.range(1, 1000).forEach(i->{
System.out.println(Thread.currentThread().getName() + " --> " + i);
});
}

7. 中断线程 interrupt()
* Interrupts this thread.
*
* <p> Unless the current thread is interrupting itself, which is
* always permitted, the {@link #checkAccess() checkAccess} method
* of this thread is invoked, which may cause a {@link
* SecurityException} to be thrown.

public void interrupt()
public static boolean interrupted()
public boolean isInterrupted()
private native boolean isInterrupted(boolean ClearInterrupted);

public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
while (true){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
System.out.println("interrupte");
e.printStackTrace();
break;
}
}
});
t1.start();

Thread.sleep(100);

System.out.println(t1.isInterrupted());
t1.interrupt();

System.out.println(t1.isInterrupted());
}

8. 优雅的结束线程

八 线程的数据同步和synchronized

九 死锁

十 线程之间的通讯

十一 消费者和生产者 wait和notifiy

十二 wait和sleep的区别

十三 线程组

十四 实现自己的LOCK

十五 捕获线程运行中的异常

十六 自定义线程池

-------------本文结束感谢您的阅读-------------
坚持原创技术分享,您的支持将鼓励我继续创作!