public class BigStar { public static void main(String[] args) { Thread t = new Test(); t.start(); for(int i = 0;i<5;i++){ System.out.println("big"+i); } } }
1 2 3 4 5 6 7 8
public class Test extends Thread{ @Override public void run(){ for(int i = 0;i<5;i++){ System.out.println("test"+i); } } }
这样就是两个线程来跑,但是谁先谁后是不确定的
这种方式编码比较简单,不利于功能的扩展
不能再继承其他的类了
必须使用start方法 注册单独的执行流程
不要把主线程的任务放到子线程之前
二:
声明实现Runnable接口的类
然后重写run方法
创建任务类对象
然后创建线程对象
1 2 3 4 5 6 7 8 9 10
public class BigStar { public static void main(String[] args) { Runnable target = new Test(); new Thread(target).start(); for(int i =0;i<=5;i++){ System.out.println("bbb"+i); } } }
1 2 3 4 5 6 7 8 9
public class Test implements Runnable{
@Override public void run() { for(int i =0;i<=5;i++){ System.out.println("aaa"+i); } } }
这是第二个实现方法
优缺点:
可是继承其他的类,实现其他的接口,扩展性强
或者是使用简化形式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
public class BigStar { public static void main(String[] args) { // 创建并启动新线程 new Thread(new Runnable() { @Override public void run() { for (int i = 0; i <= 5; i++) { System.out.println("aaa" + i); } } }).start();
// 主线程继续执行 for (int i = 0; i <= 5; i++) { System.out.println("bbb" + i); } } }
public class BigStar { public static void main(String[] args) throws ExecutionException, InterruptedException { Callable<String> callable = new Test(100); FutureTask<String> futureTask = new FutureTask<>(callable); new Thread(futureTask).start(); String rs = futureTask.get(); System.out.println(rs);
} }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
import java.util.concurrent.Callable;
public class Test implements Callable<String> { private int n;
public Test(int n) { this.n = n; }
@Override public String call() throws Exception { int sum=0; for (int i= 0;i<=n;i++){ sum+=i; } return "qiu"+sum;
public class BigStar { public static void main(String[] args) throws ExecutionException, InterruptedException { Callable<String> callable = new Test(100); FutureTask<String> futureTask = new FutureTask<>(callable); new Thread(futureTask).start(); Callable<String> callable2 = new Test(200); FutureTask<String> futureTask2 = new FutureTask<>(callable2); new Thread(futureTask2).start(); String rs = futureTask2.get(); System.out.println(rs); String rs2 = futureTask.get(); System.out.println(rs2);
} }
求取两个线程一块跑
这个方式的编码比较复杂,但是能够返回一结果
常用方法
getName
1 2 3 4 5 6 7 8 9 10 11 12 13
public class BigStar { public static void main(String[] args) { Thread t1 = new Test(); System.out.println(t1.getName()); Thread t2 = Thread.currentThread(); System.out.println(t2.getName()); for(int i =0;i<=5;i++){ System.out.println("bbb"+i); } } }
获取线程的名字
可以取获取主线程的name,一般就是main
使用setName设置线程的名字,要在线程启动之前
可以为线程添加一个String类型的数据,可以使他添加
1 2 3 4 5 6 7 8 9 10 11
public class Test extends Thread implements Runnable{ public Test(String name){ super(name); } @Override public void run() { for(int i =0;i<=5;i++){ System.out.println("aaa"+i); } } }
sleep代码用来休眠
线程按照顺序进行执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
public class BigStar { public static void main(String[] args) throws InterruptedException { Thread t1 = new Test("a"); t1.start(); t1.join(); System.out.println(t1.getName()); Thread t2 = Thread.currentThread(); t2.start(); t2.join(); System.out.println(t2.getName()); for(int i =0;i<=5;i++){ System.out.println("bbb"+i); } } }
线程安全问题
多个线程在同时操作一个共享资源时,可能出现安全问题
叫做线程安全问题
存在多个线程在同时执行
同时访问同一个共享资源
都要修改数据
为了解决线程安全问题,我们要使用线程同步方法
同步代码块
把访问共享资源的核心代码上锁
每次只允许一个线程加锁后进入
同步锁必须时同一个对象才可以
1 2 3 4 5 6 7 8 9 10 11 12 13
public class Test extends Thread implements Runnable{ public Test(String name){ super(name); } @Override public void run() { synchronized ("qq") { for(int i =0;i<=5;i++){ System.out.println("aaa"+i); } } } }
ctrl+alt+t
选择第9个就可以放进代码块
锁的范围太大
1 2 3 4 5 6 7 8 9 10 11 12 13
public class Test extends Thread implements Runnable{ public Test(String name){ super(name); } @Override public void run() { synchronized (this) { for(int i =0;i<=5;i++){ System.out.println("aaa"+i); } } } }
使用this作为锁,只锁住当前对象
静态方法使用class文件作为锁
1 2 3 4 5 6 7 8 9 10 11 12 13
public class Test extends Thread implements Runnable{ public Test(String name){ super(name); } @Override public void run() { synchronized (Test.class) { for(int i =0;i<=5;i++){ System.out.println("aaa"+i); } } } }
public class Test extends Thread implements Runnable{ private final Lock lk = new ReentrantLock(); public Test(String name){ super(name); } @Override public void run() { lk.lock(); for(int i =0;i<=5;i++){ System.out.println("aaa"+i); } lk.unlock(); } }
public class Test extends Thread implements Runnable{ private final Lock lk = new ReentrantLock(); public Test(String name){ super(name); } @Override public void run() { lk.lock(); try { for(int i =0;i<=5;i++){ System.out.println("aaa"+i); } } catch (Exception e) { throw new RuntimeException(e); } finally { lk.unlock(); } } }
把解锁操作放在finally里面就可以进行更好的实现,保证不出现bug
线程通信
线程间通过某种方式互相告知自己的状态
模型:
生产者线程负责生产数据
消费者负责消费生产者生产的数据
ps:生产–消费–生成…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
public class BigStar { public static void main(String[] args) throws InterruptedException { // 使用Lambda表达式创建并启动新线程 new Thread(() -> { for (int i = 0; i <= 5; i++) { System.out.println("aaa" + i); } }).start(); new Thread(()->{ }).start();
// 主线程继续执行 for (int i = 0; i <= 5; i++) { System.out.println("bbb" + i); } } }