创建线程:
1、继承Thread类,覆盖run()方法
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程=====:" + Thread.currentThread().getName());
}
public static void main(String[] args) {
for(int i = 0 ; i < 10 ; i++){
MyThread myThread = new MyThread();
myThread.setName("thread" + i);//设置线程名称
myThread.start(); //启动线程
}
System.out.println("主线程:" + Thread.currentThread().getName());
}
}
2、实现Runnable接口,重写run()方法,将实现Runnable的对象传入Thread对象
public class MyThreadRunnable implements Runnable {
@Override
public void run() {
System.out.println("线程===========:" + Thread.currentThread().getName());
}
public static void main(String[] args) {
for(int i = 0;i < 10 ;i ++){
MyThreadRunnable myThreadRunnable = new MyThreadRunnable();
Thread thread = new Thread(myThreadRunnable);
thread.setName("thread" + i);
thread.start();
}
System.out.println("主线程==:" + Thread.currentThread().getName());
}
}
3、实现Callable接口(有返回值)
public class MyCallable implements Callable {
private String name;
public MyCallable(String name){
this.name = name;
}
public Object call() throws Exception {
return this.name;
}
public static void main(String[] args) throws Exception{
for(int i = 0 ; i < 10 ; i++){
MyCallable myCallable = new MyCallable("runnable" + i);
FutureTask<String> task = new FutureTask<String>(myCallable);
Thread thread = new Thread(task);
thread.start();
//调用FutureTask.get()方法会阻塞主线程
String result = task.get();
System.out.println(result);
}
}
}
线程状态:
新建状态: 使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。
就绪状态: 当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。
运行状态: 如果就绪状态的线程获取 CPU 资源,就可以执行
run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。
阻塞状态: 如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:
等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞 状态。
同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
死亡状态: 一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。
守护线程: 为用户线程服务的线程(Daemon Thread)。不影响程序运行,守护线程未执行结束,虚拟机也会退出,也就是方法执行完毕。
Thread.setDaemon(true); //设置Daemo为true,则为守护线程。未设置的为用户线程
public class MyThreadRunnable implements Runnable {
@Override
public void run() {
try {
//守护线程睡眠期间虚拟机退出,守护线程不会影响虚拟机退出,用户线程会,虚拟机会等到所有用户线程执行完毕再退出
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程===========:" + Thread.currentThread().getName());
}
public static void main(String[] args) {
MyThreadRunnable myThreadRunnable = new MyThreadRunnable();
Thread thread = new Thread(myThreadRunnable);
thread.setDaemon(true);//设置为守护线程
thread.start();
System.out.println("主线程==:" + Thread.currentThread().getName());
}
}
线程的方法
Thead.sleep(): 线程睡眠,释放cpu资源。如果线程持有锁不会释放线程锁。
public static void main(String[] args) {
System.out.println("thread sleep start=====" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()));
try {
Thread.sleep(2 * 1000); //线程睡2秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread sleep end=====" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()));
}
Thread.join() : 调用线程等待被调用线程运行结束后在运行。线程同步。持有线程锁会释放线程锁。
public static void main(String[] args) throws InterruptedException {
/**
* 主线程(main线程)调用线程t的join方法,主线程会等待t线程运行结束再次运行
*/
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
});
t.start();
//t.join(100); //设置等待时间 等待超时不等待
t.join();
System.out.println(Thread.currentThread().getName());
}
Thread.yield() : 线程让步,使线程让出cpu资源,回到就绪状态继续竞争cpu资源。如果线程持有锁不会释放线程锁。
public static void main(String[] args) throws Exception{
for(int i = 0;i < 5 ;i ++){
Thread t = new Thread(new Runnable() {
@Override
public void run() {
for(int j = 0; j < 10 ;j ++){
System.out.println(Thread.currentThread().getName() + "===" + j);
/**
* 调用 yield()会使线程让出cpu资源重新从运行状态变为就绪状态(继续获取cpu资源)
* 导致输出不是0-9,中间会有其它线程的输出
*/
Thread.yield();
}
}
});
t.setName("线程" + i);
t.start();
}
}
wait() : 线程等待。释放锁。需要唤醒才继续运行,唤醒的线程需要重新获取锁才能运行。
notify()/notifyAll() : 唤醒线程。(唤醒在当前锁中wait的线程)。
notify()/notifyAll()和wait()方法需要在synchronized内部调用,使用锁对象调用。
public class Queue {
private static final List<Integer> queueList = new ArrayList<>();
/**
* 加入队列
* @param s
*/
public synchronized static void addQueue(Integer s){
queueList.add(s);
Queue.class.notifyAll();
}
/**
* 队列中取出
* @return
*/
public synchronized static Integer getQueue(){
while (queueList.isEmpty()){
try {
Queue.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Integer str = queueList.get(0);
queueList.remove(0);
return str;
}
public static void main(String[] args) throws InterruptedException {
//消费
new Thread(() -> {
//读取队列中的数据
while (true){
System.out.println("取出================:" + Queue.getQueue());
}
}).start();
//队列中存入
for(int i = 0 ;i < 3000 ;i ++){
Thread.sleep(1000);
final int finalI = i;
Thread t = new Thread(new Runnable() {
public void run() {
Queue.addQueue(finalI);
System.out.println("插入队列完成:" + finalI);
}
});
System.out.println("准备插入队列:" + finalI);
t.start();
}
}
}
Thread.interrupt() : 中断线程。线程正常运行外部调用interrupt()方法,线程的isInterrupted()会为true,如果线程正在sleep(),则会抛出InterruptedException异常,根据具体业编写中断线程的代码。
public class InterruptThread extends Thread {
@Override
public void run() {
//isInterrupted()为false则未被中断
while (!isInterrupted()){
System.out.println("线程:" + getName());
try {
Thread.sleep(10 * 1000);
} catch (InterruptedException e) {
//线程处于睡眠状态,外部调用该线程interrupt()方法,会抛出InterruptedException异常
return;
}
}
}
public static void main(String[] args) {
InterruptThread thread = new InterruptThread();
thread.start();
try {
Thread.sleep(2 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
}