文章目录
Java 实现线程的三种方式
说明: Java 不支持多继承, 所以继承了 Thread 类就无法继承其它类, 但是可以实现多个接口.
1. 继承 Thread 类, 重写 run 方法
public class ThreadDemo {
@Test
public void testThread() {
new MyThread().start();
try {
Thread.sleep(1000);
}catch (Exception e) {
e.printStackTrace();
}
}
}
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("===> 线程: " + Thread.currentThread().getName() + " - " + i);
}
}
}
2. 实现 Runnable 接口, 重写 run 方法
public class RunnableDemo {
@Test
public void testRunnable() {
Thread thread = new Thread(new MyRunnable());
thread.start();
try {
Thread.sleep(1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("===> 线程: " + Thread.currentThread().getName() + " - " + i);
}
}
}
3. 实现 Callable 接口, 重写 call 方法
public class CallableDemo {
@Test
public void testCallable() throws Exception{
FutureTask<String> futureTask = new FutureTask<>(new MyCallable());
Thread thread = new Thread(futureTask);
thread.start();
System.out.println("===> 获取线程执行结果: " + futureTask.get());
try {
Thread.sleep(1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
for (int i = 0; i < 10; i++) {
System.out.println("===> 线程: " + Thread.currentThread().getName() + " - " + i);
}
return "线程执行完毕";
}
}
Java 为什么会产生多线程安全问题 ?
Java中的线程安全问题是指当多个线程同时访问和操作同一数据时,由于线程调度的非确定性,可能导致数据的不一致和错误.
多线程问题例子 - 卖票:
public class BuyTicketsMultiThreads {
private static int tickets = 30; // 多个线程访问操作修改的相同的资源
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> {
while (true) {
if (tickets > 0) {
System.out.println("===> 售票员: " + Thread.currentThread().getName() + ", 售出票号为: " + tickets);
tickets--; // 多线程问题, 因为这里的操作不是原子性
} else {
break;
}
}
}).start();
}
}
}
/*
===> 售票员: Thread-0, 售出票号为: 30
===> 售票员: Thread-0, 售出票号为: 29
===> 售票员: Thread-0, 售出票号为: 28
===> 售票员: Thread-0, 售出票号为: 27
===> 售票员: Thread-6, 售出票号为: 30
===> 售票员: Thread-9, 售出票号为: 30
===> 售票员: Thread-7, 售出票号为: 30
===> 售票员: Thread-8, 售出票号为: 30
===> 售票员: Thread-4, 售出票号为: 30
===> 售票员: Thread-2, 售出票号为: 30
===> 售票员: Thread-0, 售出票号为: 26
===> 售票员: Thread-6, 售出票号为: 25
===> 售票员: Thread-5, 售出票号为: 30
===> 售票员: Thread-1, 售出票号为: 30
===> 售票员: Thread-3, 售出票号为: 30
===> 售票员: Thread-9, 售出票号为: 24
===> 售票员: Thread-7, 售出票号为: 23
===> 售票员: Thread-7, 售出票号为: 13
===> 售票员: Thread-8, 售出票号为: 22
===> 售票员: Thread-4, 售出票号为: 21
===> 售票员: Thread-2, 售出票号为: 20
===> 售票员: Thread-0, 售出票号为: 19
===> 售票员: Thread-6, 售出票号为: 18
===> 售票员: Thread-5, 售出票号为: 17
===> 售票员: Thread-1, 售出票号为: 16
===> 售票员: Thread-3, 售出票号为: 15
===> 售票员: Thread-9, 售出票号为: 14
===> 售票员: Thread-7, 售出票号为: 12
===> 售票员: Thread-8, 售出票号为: 11
===> 售票员: Thread-4, 售出票号为: 10
===> 售票员: Thread-2, 售出票号为: 9
===> 售票员: Thread-0, 售出票号为: 8
===> 售票员: Thread-6, 售出票号为: 7
===> 售票员: Thread-5, 售出票号为: 6
===> 售票员: Thread-1, 售出票号为: 5
===> 售票员: Thread-3, 售出票号为: 4
===> 售票员: Thread-9, 售出票号为: 3
===> 售票员: Thread-7, 售出票号为: 2
===> 售票员: Thread-8, 售出票号为: 1
*/
多线程卖票问题解决1 (synchronized 锁)
public class BuyTicketsMultiThreads {
private static volatile int tickets = 30;
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> {
while (true) {
if (tickets > 0) {
synchronized (BuyTicketsMultiThreads.class) {
if (tickets > 0) {
System.out.println("===> 售票员: " + Thread.currentThread().getName() + ", 售出票号为: " + tickets);
tickets--;
}
}
} else {
break;
}
}
}).start();
}
}
}
多线程卖票问题解决2 (并发包工具类)
public class BuyTicketsWithConCurrent {
private static final AtomicInteger TICKETS = new AtomicInteger(30);
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> {
while (true) {
if (TICKETS.get() > 0) {
System.out.println("===> 售票员: " + Thread.currentThread().getName() + ", 售出票号为: " + TICKETS.getAndDecrement());
} else {
break;
}
}
}).start();
}
}
}