创建线程方式 重要
继承Thead
实现Runnable接口,重写run方法
package com.qfedu.thread;
/**
* 实现Runnable接口,重写run()方法
* @author renrui
*
*/
public class MyRunnable implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
package com.qfedu.thread;
public class App {
public static void main(String[] args) {
// TODO Auto-generated method stub
// 使用线程,推荐通过实现Runnable接口方式
MyRunnable myRunnable = new MyRunnable();
// 创建线程
Thread t1 = new Thread(myRunnable);
// 获取优先级 默认优先级5
System.out.println(t1.getPriority());
// 设置优先级 1-10
// t1.setPriority(10);
t1.setPriority(Thread.MAX_PRIORITY);
Thread t2 = new Thread(myRunnable);
// 启动线程
t1.start();
t2.start();
// 使用匿名内部类
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
});
t3.start();
}
}
java中线程的状态 重要
6状态
1)新建状态new: 调用new 创建对象
2)可运行状态runnable: 调用start(),进入可运行状态,可以认为可运行状态中包含就绪和运行两个状态
3)阻塞状态blocking:某个线程调用同步方法,还没有释放锁时,其他线程也访问该方法,进行阻塞状态。当线程执行完毕释放锁,那些阻塞的线程进入可运行状态
4)等待状态waiting:调用wait()/join()等方法后,线程进入等待状态。当join对应的线程执行完毕,或者wait()的线程被唤醒,等待的线程进入可运行状态
5)计时等待状态time waiting: 和等待状态类型,调用sleep(long)/wait(long)/join(long)等方法,进入计时等待状态
6)终止状态terminated:run方法执行完毕,或者线程异常,进入终止状态
线程的调度
sleep 线程睡眠
某个线程中调用sleep方法,该线程睡眠,进入计时等待状态
package com.qfedu.sleep;
public class App {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyThread t = new MyThread();
t.start();
try {
// 受检异常
// 线程睡眠 参数表示睡眠时间 单位毫秒
// main方法中调用sleep,主线程休眠
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for(int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
class MyThread extends Thread {
@Override
public void run() {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for(int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
join 了解
线程插入 A 线程中,调用B.join() B线程就会插队,B线程执行完,执行其他线程逻辑
package com.qfedu.join;
public class App {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyThread t = new MyThread();
t.start();
for(int i = 0; i < 500; i++) {
if(i == 20) {
try {
// 线程插队
// main方法中调用join方法的,main主线程进入等待状态
// t线程插队,插队的线程执行完毕,等待的线程才会继续执行
// t.join();
// 线程插队时,指定一个时间,单位毫秒
// 插队的线程执行完毕,或者插队时间到,等待的线程进入可运行状态
// main和t共同竞争cpu资源
t.join(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
class MyThread extends Thread {
@Override
public void run() {
for(int i = 0; i < 500; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
yield 了解
线程礼让,某个线程中调用yield方法,该线程进入就绪状态
package com.qfedu.yield;
public class App {
public static void main(String[] args) {
// TODO Auto-generated method stub
Product p = new Product();
Customer c = new Customer();
p.start();
c.start();
}
}
class Product extends Thread {
@Override
public void run() {
for(int i = 0; i < 100; i++) {
if(i == 8) {
// 调用yield方法之前,线程之间是竞争关系
// 线程礼让
// 调用礼让方法的线程进入就绪状态
// 和其他线程一起竞争cpu资源
Thread.yield();
}
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
class Customer extends Thread {
@Override
public void run() {
for(int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
线程同步 重要
主要为了解决线程安全的问题
多个线程访问线程共享的数据时 ,要注意线程安全问题
课件中,使用同步机制,实现线程同步
同步代码块
synchronized(锁对象) {}
同步方法
synchronized 返回值 方法名(参数) {}
注意:锁对象需要唯一,多个需要共享一把锁
package com.qfedu.syn;
public class App {
public static void main(String[] args) {
// TODO Auto-generated method stub
Ticket ticket = new Ticket();
// 启动了50个线程
for(int i = 0; i < 50; i++) {
Thread t = new Thread(ticket);
t.start();
}
}
}
class Ticket implements Runnable {
// 初始有100张票
// 50个线程共享num
private int num = 100;
@Override
public void run() {
// TODO Auto-generated method stub
// num--;
// System.out.println("剩余票数:" + num);
// 调用同步方法
// A线程先抢到cpu资源,执行同步方法,加锁,
// A线程执行代码的过程中,失去cpu的控制权(调度系统将cpu分配给其他线程),B线程抢到cpu,执行同步方法
// B执行同步方法时,A线程还没有执行完代码,锁依旧存在,B就会阻塞,等着A释放锁
// A释放锁后,其他阻塞的线程进入就绪状态,哪个线程先抢到cpu,哪个线程就可以执行同步方法,并加锁
// 注意:A执行完,释放锁,其他线程,比如BCDEF等线程,还需要抢占cpu资源,而不是B先执行
// 阻塞的线程会在“锁池”中记录(了解)
// show();
// 同步代码块
// 基本语法:synchronized(代表锁的对象) {执行的逻辑}
// 50个线程共用一个ticket对象,this表示当前的ticket对象,所以this可作为多个线程公用的锁
synchronized (this) {
// synchronized (Ticket.class) { // 该写法了解一下 Ticket.class表示获取Ticket的Class对象
num--;
System.out.println(Thread.currentThread().getName() + ",剩余票数:" + num);
}
}
// 同步方法,在代码中“锁”也是对象,同步方法中,使用的锁是this对象
public synchronized void show() {
num--;
System.out.println(Thread.currentThread().getName() + ",剩余票数:" + num);
}
}
单例设计模式 次重要
某个类,在整个程序中只能有一个对象的时候,就可以使用单例模式
懒汉式
package com.qfedu.singleton;
/**
* 懒汉式 考虑多线程环境的线程安全问题
* @author renrui
*
*/
public class Singleton {
private static Singleton singleton = null;
// 构造方法设置成私有的,类外不能通过new 创建对象
private Singleton() {}
// 在类内部创建对象
public static synchronized Singleton getInstance() {
if(singleton == null) {
singleton = new Singleton();
return singleton;
} else {
return singleton;
}
}
}
饿汉式
package com.qfedu.singleton;
/**
* 饿汉式 推荐
* @author renrui
*
*/
public class Singleton2 {
// 类加载的时候创建静态变量,只会执行一次
// 定义静态变量,直接创建对象并赋值
private static Singleton2 singleton2 = new Singleton2();
private Singleton2() {}
public static Singleton2 getInstance() {
return singleton2;
}
}