一:Java中三种多线程的实现方式
在Java中实现多线程有两种途径,
- 继承Thread类,重写run方法,多线程启动的方法,就是start方法。(单继承的局限)
public class TestThread extends Thread {
private String name;
public TestThread(String name) {
this.name = name;
}
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println(this.name + "-->" + i);
}
}
public static void main(String[] args) {
TestThread thread1 = new TestThread("线程1");
TestThread thread2 = new TestThread("线程2");
TestThread thread3 = new TestThread("线程3");
thread1.start();
thread2.start();
thread3.start();
}
}
- 实现Runnable接口,并且重写run方法。多线程的启动还是Thread的start方法。
public class TestRunnable implements Runnable {
private String name;
public TestRunnable(String name) {
this.name = name;
}
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println(this.name + "-->" + i);
}
}
public static void main(String[] args) {
TestRunnable thread1 = new TestRunnable("线程1");
TestRunnable thread2 = new TestRunnable("线程2");
TestRunnable thread3 = new TestRunnable("线程3");
new Thread(thread1).start();
new Thread(thread2).start();
new Thread(thread3).start();
}
}
两种方式的区别:
- 实现Runnable接口解决了单继承的局限,Thread类实现了Runable接口
- 线程资源共享,Runnable更好的诠释了数据共享,多线程访问同一资源
public static void main(String[] args) {
TestRunnable thread1 = new TestRunnable("线程1");
new Thread(thread1).start();
new Thread(thread1).start();
new Thread(thread1).start();
}
jdk1.5的新特性,线程执行完接收返回值,也是线程实现的第三种方式,
package com.java.thread;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class TestCallable implements Callable<String> {
private int ticket = 10;
@Override
public String call() throws Exception {
for (int i = 0; i < 100; i++) {
if (ticket > 0) {
System.out.println("卖票,票数=" + ticket--);
}
}
return "票卖完了";
}
public static void main(String[] args) throws Exception {
TestCallable testCallable1 = new TestCallable();
TestCallable testCallable2 = new TestCallable();
FutureTask<String> futureTask1 = new FutureTask<>(testCallable1);
FutureTask<String> futureTask2 = new FutureTask<>(testCallable2);
new Thread(futureTask1).start();
new Thread(futureTask2).start();
System.out.println("futureTask1 = " + futureTask1.get());
System.out.println("futureTask2 = " + futureTask2.get());
}
}
二:线程的命名与取得,Thread.currentThread().getName(),线程能够自动命名
Thread(Runnable target, String name)
Allocates a new
Thread
object.setName(String name)
Changes the name of this thread to be equal to the argument
name
.-
getName()
Returns this thread's name
public class TestRunnable implements Runnable {
private String name;
public TestRunnable(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
TestRunnable thread1 = new TestRunnable("线程1");
new Thread(thread1,"线程1").start();
new Thread(thread1).start();
new Thread(thread1,"线程3").start();
}
}
每一个JVM启动,至少启动两个线程
- main线程,以及程序的子线程
- gc线程,负责垃圾回收
三:线程的休眠
- Thread.sleep(1000); 有先后差别
四:线程的优先级Thread类里面提供的两个方法,以及三个常量
setPriority(int newPriority)
Changes the priority of this thread.
-
Returns this thread's priority.
-
MIN_PRIORITY
The minimum priority that a thread can have.
-
The maximum priority that a thread can have.
-
The default priority that is assigned to a thread.
public static void main(String[] args) {
TestThread thread1 = new TestThread("线程1");
TestThread thread2 = new TestThread("线程2");
TestThread thread3 = new TestThread("线程3");
thread1.setPriority(MAX_PRIORITY);
thread2.setPriority(MIN_PRIORITY);
thread3.setPriority(NORM_PRIORITY);
thread1.start();
thread2.start();
thread3.start();
}
五:总结
- 主线程属于中等优先级,
- Thread.currentThread()可以获取当前线程的对象。
六:同步问题
多个线程访问同一个资源需要考虑的问题,4个人卖5张票,在判断和修改是分开执行的,最后一张票出现了资源的延迟,
如何解决同步的问题
当有线程在执行的时候,其他的线程先等待。在Java中要想实现线程的同步需要使用synchronized关键字。
使用方式,
- 同步代码块
- 同步方法
Java中有四种代码块,普通代码块,构造块,静态块,同步块。
- 以下是同步代码块,
- 以下是同步方法,
public class TestSynchronized implements Runnable {
private int ticket = 50;
@Override
public void run() {
try {
for (int i = 0; i < 200; i++) {
//卖票的过程
if (sell()) {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public synchronized boolean sell() throws InterruptedException {
if (ticket > 0) {
// Thread.sleep(200);
System.out.println(Thread.currentThread().getName() + "...票数=" + this.ticket--);
return false;
} else {
return true;
}
}
public static void main(String[] args) {
TestSynchronized thread0 = new TestSynchronized();
new Thread(thread0,"票贩子A").start();
new Thread(thread0,"票贩子B").start();
new Thread(thread0,"票贩子C").start();
new Thread(thread0,"票贩子D").start();
}
}
死锁:是一个线程对象等待另一个线程对象执行完毕后的操作结果,同步过多可能发生死锁。
多个线程访问一个资源需要考虑哪些问题,
- 同步问题,可以使用同步代码块,也可以使用同步方法
- 过多的使用同步可能造成死锁
七:生产者和消费者
- 生产者负责生产数据,消费者负责取走数据
- 生产者每生产一组数据,消费者就取走一组数据
等待与唤醒,
- super.wait();
- super.notify();
sleep和wait得区别,
- sleep是Thread类的方法,wait是Object类的方法
- sleep可以设置休眠时间,时间一到自动唤醒,而wait需要notify去唤醒。