Java多线程创建及典型实例(多线程买票)
- 多线程
- 1. Thread
- 2. Runnable
- 3. 线程通信
- 4. Callable
- 5. 线程池
- 多线程卖票实例
- 1. 继承Thread类(存在线程安全问题)
- 2. 实现Runnable接口(存在线程安全问题)
- 3. 对线程安全问题的解决
- 3.1 Runnable(同步代码块)
- 3.2 Thread(同步代码块)
- 3.3 Runnable(同步方法)
- 3.4 Thread(同步方法)
- 3.5 Lock解决线程安全问题
多线程
1. Thread
第一种方式创建多线程
package JavaPackage_13;
public class JavaCode {
public static void main(String[] args) {
new MyThread().start();
System.out.println(Thread.currentThread().getName()); // main
}
}
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(i + Thread.currentThread().getName());
}
}
}
package JavaPackage_13;
public class JavaCode {
public static void main(String[] args) throws InterruptedException {
new MyThread().start();
Thread.sleep(10);
System.out.println(Thread.currentThread().getName()); // main
Thread.currentThread().setName("主线程");
System.out.println(Thread.currentThread().getName());
System.out.println(Thread.currentThread().isAlive());
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
System.out.println(Thread.currentThread().getPriority()); // 5
}
}
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(i + Thread.currentThread().getName() + " " + getPriority());
}
}
}
2. Runnable
第二种方式创建多线程
package JavaPackage_13;
public class JavaCode {
public static void main(String[] args) {
Window window = new Window();
Thread thread1 = new Thread(window);
Thread thread2 = new Thread(window);
Thread thread3 = new Thread(window);
thread1.setName("窗口1");
thread2.setName("窗口2");
thread3.setName("窗口3");
thread1.start();
thread2.start();
thread3.start();
}
}
class Window implements Runnable {
private int ticket = 100;
@Override
public void run() {
while (true) {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":票号:" + ticket--);
} else {
break;
}
}
}
}
3. 线程通信
线程通信:线程1、2交替打印数字1-100
package JavaPackage_13;
public class JavaCode {
public static void main(String[] args) {
Number number = new Number();
Thread thread1 = new Thread(number);
Thread thread2 = new Thread(number);
thread1.start();
thread2.start();
}
}
class Number implements Runnable {
private int num = 1;
@Override
public void run() {
while (true) {
synchronized (this) {
notify();
if (num < 100) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + num++);
}
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
4. Callable
第三种方式创建多线程
package JavaPackage_13;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class JavaCode {
public static void main(String[] args) {
MyThread myThread = new MyThread();
FutureTask<Integer> futureTask = new FutureTask<Integer>(myThread);
Thread thread = new Thread(futureTask);
thread.start();
try {
// 获取返回值
Integer sum = futureTask.get();
System.out.println(sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class MyThread implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i <= 100; i++) {
sum += i;
}
return sum;
}
}
5. 线程池
第四种方式创建多线程
线程池创建多线程
package JavaPackage_13;
import java.util.concurrent.*;
public class JavaCode {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10); // 接口
ThreadPoolExecutor service = (ThreadPoolExecutor) executorService;
//设置属性
service.setCorePoolSize(15);
try {
System.out.println(executorService.submit(new MyThread()).get());// 适用于Callable
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
executorService.execute(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(i + Thread.currentThread().getName());
}
}
}); // 适用于Runnable
//关闭连接池
executorService.shutdown();
}
}
class MyThread implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i <= 100; i++) {
sum += i;
}
return sum;
}
}
多线程卖票实例
1. 继承Thread类(存在线程安全问题)
package JavaPackage_13;
public class JavaCode {
public static void main(String[] args) {
Window window1 = new Window();
Window window2 = new Window();
Window window3 = new Window();
window1.setName("窗口1");
window2.setName("窗口2");
window3.setName("窗口3");
window1.start();
window2.start();
window3.start();
}
}
class Window extends Thread {
private static int ticket = 100;
@Override
public void run() {
while (true) {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + ":票号:" + ticket--);
} else {
break;
}
}
}
}
2. 实现Runnable接口(存在线程安全问题)
package JavaPackage_13;
public class JavaCode {
public static void main(String[] args) {
Window window = new Window();
Thread thread1 = new Thread(window);
Thread thread2 = new Thread(window);
Thread thread3 = new Thread(window);
thread1.setName("窗口1");
thread2.setName("窗口2");
thread3.setName("窗口3");
thread1.start();
thread2.start();
thread3.start();
}
}
class Window implements Runnable {
private int ticket = 100;
@Override
public void run() {
while (true) {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":票号:" + ticket--);
} else {
break;
}
}
}
}
窗口1:票号:100
窗口3:票号:100
窗口2:票号:100
窗口2:票号:99
窗口3:票号:97
窗口1:票号:98
窗口2:票号:96
窗口3:票号:95
窗口1:票号:94
窗口2:票号:93
窗口3:票号:92
窗口1:票号:91
窗口3:票号:90
窗口2:票号:90
窗口1:票号:89
窗口3:票号:88
窗口2:票号:87
窗口1:票号:86
窗口3:票号:85
窗口2:票号:84
窗口1:票号:83
窗口3:票号:82
窗口2:票号:81
窗口1:票号:80
窗口3:票号:79
窗口2:票号:78
窗口1:票号:77
窗口3:票号:76
窗口2:票号:75
窗口1:票号:74
窗口3:票号:73
窗口2:票号:72
窗口1:票号:71
窗口3:票号:70
窗口2:票号:69
窗口1:票号:68
窗口3:票号:67
窗口2:票号:66
窗口1:票号:65
窗口3:票号:64
窗口2:票号:63
窗口1:票号:62
窗口3:票号:61
窗口2:票号:60
窗口1:票号:59
窗口3:票号:58
窗口2:票号:57
窗口1:票号:56
窗口3:票号:55
窗口2:票号:54
窗口1:票号:53
窗口3:票号:52
窗口2:票号:51
窗口1:票号:50
窗口3:票号:49
窗口2:票号:48
窗口1:票号:47
窗口3:票号:46
窗口2:票号:45
窗口1:票号:44
窗口3:票号:43
窗口2:票号:42
窗口1:票号:41
窗口3:票号:40
窗口2:票号:39
窗口1:票号:38
窗口3:票号:37
窗口2:票号:36
窗口1:票号:35
窗口3:票号:34
窗口2:票号:33
窗口1:票号:32
窗口3:票号:31
窗口2:票号:30
窗口1:票号:29
窗口3:票号:28
窗口2:票号:27
窗口1:票号:26
窗口3:票号:25
窗口2:票号:24
窗口1:票号:23
窗口3:票号:22
窗口2:票号:21
窗口1:票号:20
窗口3:票号:19
窗口2:票号:18
窗口1:票号:17
窗口3:票号:16
窗口2:票号:15
窗口1:票号:14
窗口3:票号:13
窗口2:票号:12
窗口1:票号:11
窗口3:票号:10
窗口2:票号:9
窗口1:票号:8
窗口3:票号:7
窗口2:票号:6
窗口1:票号:5
窗口3:票号:4
窗口2:票号:3
窗口1:票号:2
窗口3:票号:1
窗口2:票号:0
窗口1:票号:-1
Process finished with exit code 0
3. 对线程安全问题的解决
通过同步机制解决线程安全问题
3.1 Runnable(同步代码块)
可以考虑使用this充当同步监视器
synchronized(同步监视器[锁]){ // 任何一个类的对象都可以充当锁 多个线程必须要共用同一把锁
被同步的代码
}
操作同步代码时,只能有一个线程参与,其他线程等待,效率低。
package JavaPackage_13;
public class JavaCode {
public static void main(String[] args) {
Window window = new Window();
Thread thread1 = new Thread(window);
Thread thread2 = new Thread(window);
Thread thread3 = new Thread(window);
thread1.setName("窗口1");
thread2.setName("窗口2");
thread3.setName("窗口3");
thread1.start();
thread2.start();
thread3.start();
}
}
class Window implements Runnable {
private int ticket = 100;
@Override
public void run() {
while (true) {
synchronized (this) {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":票号:" + ticket--);
} else {
break;
}
}
}
}
}
窗口1:票号:100
窗口1:票号:99
窗口1:票号:98
窗口1:票号:97
窗口1:票号:96
窗口1:票号:95
窗口1:票号:94
窗口1:票号:93
窗口1:票号:92
窗口1:票号:91
窗口1:票号:90
窗口1:票号:89
窗口1:票号:88
窗口1:票号:87
窗口1:票号:86
窗口1:票号:85
窗口1:票号:84
窗口1:票号:83
窗口1:票号:82
窗口1:票号:81
窗口1:票号:80
窗口1:票号:79
窗口1:票号:78
窗口1:票号:77
窗口1:票号:76
窗口1:票号:75
窗口1:票号:74
窗口1:票号:73
窗口1:票号:72
窗口1:票号:71
窗口1:票号:70
窗口1:票号:69
窗口1:票号:68
窗口1:票号:67
窗口1:票号:66
窗口1:票号:65
窗口1:票号:64
窗口1:票号:63
窗口1:票号:62
窗口1:票号:61
窗口1:票号:60
窗口1:票号:59
窗口1:票号:58
窗口1:票号:57
窗口1:票号:56
窗口1:票号:55
窗口1:票号:54
窗口1:票号:53
窗口1:票号:52
窗口1:票号:51
窗口1:票号:50
窗口1:票号:49
窗口1:票号:48
窗口1:票号:47
窗口1:票号:46
窗口1:票号:45
窗口1:票号:44
窗口1:票号:43
窗口1:票号:42
窗口1:票号:41
窗口1:票号:40
窗口1:票号:39
窗口1:票号:38
窗口1:票号:37
窗口1:票号:36
窗口1:票号:35
窗口1:票号:34
窗口1:票号:33
窗口1:票号:32
窗口1:票号:31
窗口1:票号:30
窗口1:票号:29
窗口1:票号:28
窗口1:票号:27
窗口1:票号:26
窗口1:票号:25
窗口1:票号:24
窗口1:票号:23
窗口1:票号:22
窗口1:票号:21
窗口1:票号:20
窗口1:票号:19
窗口1:票号:18
窗口1:票号:17
窗口1:票号:16
窗口1:票号:15
窗口1:票号:14
窗口1:票号:13
窗口1:票号:12
窗口1:票号:11
窗口1:票号:10
窗口1:票号:9
窗口1:票号:8
窗口1:票号:7
窗口1:票号:6
窗口1:票号:5
窗口1:票号:4
窗口1:票号:3
窗口1:票号:2
窗口1:票号:1
Process finished with exit code 0
3.2 Thread(同步代码块)
可以考虑使用当前类xxx.class充当同步监视器
package JavaPackage_13;
public class JavaCode {
public static void main(String[] args) {
Window window1 = new Window();
Window window2 = new Window();
Window window3 = new Window();
window1.setName("窗口1");
window2.setName("窗口2");
window3.setName("窗口3");
window1.start();
window2.start();
window3.start();
}
}
class Window extends Thread {
private static int ticket = 100;
@Override
public void run() {
while (true) {
synchronized (Window.class) { // 不能使用this
if (ticket > 0) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":票号:" + ticket--);
} else {
break;
}
}
}
}
}
窗口1:票号:100
窗口1:票号:99
窗口1:票号:98
窗口1:票号:97
窗口1:票号:96
窗口1:票号:95
窗口1:票号:94
窗口1:票号:93
窗口1:票号:92
窗口1:票号:91
窗口1:票号:90
窗口1:票号:89
窗口1:票号:88
窗口1:票号:87
窗口1:票号:86
窗口1:票号:85
窗口1:票号:84
窗口1:票号:83
窗口1:票号:82
窗口1:票号:81
窗口1:票号:80
窗口1:票号:79
窗口1:票号:78
窗口1:票号:77
窗口1:票号:76
窗口1:票号:75
窗口1:票号:74
窗口1:票号:73
窗口1:票号:72
窗口1:票号:71
窗口1:票号:70
窗口1:票号:69
窗口1:票号:68
窗口1:票号:67
窗口1:票号:66
窗口1:票号:65
窗口1:票号:64
窗口1:票号:63
窗口1:票号:62
窗口1:票号:61
窗口1:票号:60
窗口1:票号:59
窗口1:票号:58
窗口1:票号:57
窗口1:票号:56
窗口1:票号:55
窗口1:票号:54
窗口1:票号:53
窗口1:票号:52
窗口1:票号:51
窗口1:票号:50
窗口1:票号:49
窗口1:票号:48
窗口1:票号:47
窗口1:票号:46
窗口1:票号:45
窗口1:票号:44
窗口1:票号:43
窗口1:票号:42
窗口1:票号:41
窗口1:票号:40
窗口1:票号:39
窗口1:票号:38
窗口1:票号:37
窗口1:票号:36
窗口1:票号:35
窗口1:票号:34
窗口1:票号:33
窗口1:票号:32
窗口1:票号:31
窗口1:票号:30
窗口1:票号:29
窗口1:票号:28
窗口1:票号:27
窗口1:票号:26
窗口1:票号:25
窗口1:票号:24
窗口1:票号:23
窗口1:票号:22
窗口1:票号:21
窗口1:票号:20
窗口1:票号:19
窗口3:票号:18
窗口3:票号:17
窗口3:票号:16
窗口3:票号:15
窗口3:票号:14
窗口3:票号:13
窗口3:票号:12
窗口3:票号:11
窗口3:票号:10
窗口3:票号:9
窗口3:票号:8
窗口3:票号:7
窗口3:票号:6
窗口3:票号:5
窗口3:票号:4
窗口3:票号:3
窗口3:票号:2
窗口3:票号:1
Process finished with exit code 0
3.3 Runnable(同步方法)
如果操作共享数据的代码完整的声明在一个方法中,可以将这个方法声明为同步的
package JavaPackage_13;
public class JavaCode {
public static void main(String[] args) {
Window window = new Window();
Thread thread1 = new Thread(window);
Thread thread2 = new Thread(window);
Thread thread3 = new Thread(window);
thread1.setName("窗口1");
thread2.setName("窗口2");
thread3.setName("窗口3");
thread1.start();
thread2.start();
thread3.start();
}
}
class Window implements Runnable {
private int ticket = 100;
@Override
public void run() { //public synchronized void run() synchronized包含的同步代码:不能包多也不能包少
while (true) {
show();
}
}
private synchronized void show(){ // 同步监视器:this
if (ticket > 0) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":票号:" + ticket--);
}
}
}
3.4 Thread(同步方法)
package JavaPackage_13;
public class JavaCode {
public static void main(String[] args) {
Window window1 = new Window();
Window window2 = new Window();
Window window3 = new Window();
window1.setName("窗口1");
window2.setName("窗口2");
window3.setName("窗口3");
window1.start();
window2.start();
window3.start();
}
}
class Window extends Thread {
private static int ticket = 100;
@Override
public void run() {
while (true) {
show();
}
}
public static synchronized void show(){ // 同步监视器:Window.class
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":票号:" + ticket--);
}
}
}
3.5 Lock解决线程安全问题
package JavaPackage_13;
import java.util.concurrent.locks.ReentrantLock;
public class JavaCode {
public static void main(String[] args) {
Window window1 = new Window();
Window window2 = new Window();
Window window3 = new Window();
window1.setName("窗口1");
window2.setName("窗口2");
window3.setName("窗口3");
window1.start();
window2.start();
window3.start();
}
}
class Window extends Thread {
private static int ticket = 100;
private static ReentrantLock lock = new ReentrantLock(true); // 公平锁
@Override
public void run() {
while (true) {
try {
//调用lock()
lock.lock();
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":票号:" + ticket--);
} else {
break;
}
} finally {
//调用unlock()
lock.unlock();
}
}
}
}