多线程
线程与进程的区别
进程: 软件在内存中分配的空间 工厂的一个车间,只能单个车间运行
存储在硬盘的文件由cpu加载到内存,形成一个进程
线程:进程的一个执行路径 车间的多个工人
多线程的程序真的是在同时执行吗?不是 底层是一个个在执行单核cpu多线程
多线程提高效率是指提高了CPU的利用率
多线程开启后,只是有了执行资格,但真正的执行要看cpu何时执行
实现多线程的两种方法
继承Thread
继承Thread,重写run方法(线程任务),构建子类对象,调用start方法
实现runable接口*******************
实现runnable接口,重写run方法(线程任务),创建子类对象c
创建Thread对象,将c传入构造方法中,通过Thread对象调用start
线程任务 vs 线程对象
run() Thread对象包括Thread及其子类
两种方法的比较:
有的类无法继承thread,可以通过实现runable接口的方式,解决单继承的问题;
把线程任务和线程对象分开了,只用把线程任务创建一次,无需定义静态变量;
runable接口比较方便
start与run的区别
run知识普通方法调用 并没开启新线程
star开启新线程,自动调用run方法
run与main方法的区别
主线程的任务定义在main方法中
自定义线程的任务定义在run方法中
线程中常用方法
Thread.currentThread 获取当前线程 主线程的名字是main
getName() setName ()
Thread.currentThread.getName t1.getName()
线程阻塞
Thread.sleep(2000)毫秒值; 类名调用 sleep在哪个线程中,就让哪个暂停
join 对象调用 本线程先执行 阻塞其所在的线程 只控制两个线程
Thread.interrupt 叫醒一个被阻塞的线程 会抛出一个异常
public class ppppl {
public static void main(String[] args) throws InterruptedException {
mysx mysx = new mysx();//创建子类对象
mysx.setName("子线程1");
mysx as = new mysx();
as.setName("子线程2");
as.start();
as.join();//优先执行我,阻断其所在的线程
mysx.start(); //开启多线程
mysx.interrupt(); //如果去掉,会直接打断子线程的阻塞
System.out.println(Thread.currentThread().getName()); //获取主线程名称 main
for (int i = 0; i< 50; i++) {
Thread.currentThread().setName("主线程"); //修改线程名称
Thread.sleep(3);
System.out.println(Thread.currentThread().getName()+"____________________" + i + "次");//获取线程名称
}
}
}
class mysx extends Thread { //继承Thread
@Override
public void run() { //重写run方法
try {
Thread.sleep(5000);//父类没有抛 ,所以子类也不能抛
} catch (InterruptedException e1) {
e1.printStackTrace();
}
for (int i = 0; i < 50; i++) {
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "=============================" + i + "次"); // 获取线程的名字
}
}
}
解救主线程
public class MapDemo {
public static void main(String[] args){
Person p = new Person(Thread.currentThread());
p.start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("over");
}
}
class Person extends Thread{
Thread th;
public Person(Thread th) { //通过构造方法,将主线程传入,进而执行interrupt
this.th = th;
}
public void run(){
try {
sleep(40); //保证主线程已经进入sleep状态
} catch (InterruptedException e) {
e.printStackTrace();
}
th.interrupt();
}
}
线程的生命周期图
线程的整个状态
线程安全问题
锁对象 synchronized :多个线程必须是同一个锁对象 通常用this.getClass
同步代码块 *********
可能会出现死锁,最好不要锁嵌套锁
synchronized(锁对象){代码块}
public class MapDemo {
public static void main(String[] args) {
ticket tt = new ticket();
Thread t1 = new Thread(tt);
Thread t2 = new Thread(tt);
Thread t3 = new Thread(tt);
t1.start();
t2.start();
t3.start();
}
}
class ticket implements Runnable {
static int t = 100;
public void run() {
while (true) {
synchronized (this.getClass()) {
if (t > 0) {
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售" + t-- + "张票");
} else {
break;
}
}
}
}
}
public class MapDemo {
public static void main(String[] args) {
ticket t = new ticket();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
t1.start();
t2.start();
t3.start();
}
}
class ticket implements Runnable {
static int t = 100;
ReentrantLock lock = new ReentrantLock();
public void run() {
while (true) {
lock.lock();
try {
if (t > 0) {
Thread.sleep(30);
System.out.println(Thread.currentThread().getName() + "正在出售" + t-- + "张票");
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
lock.unlock();
}
}
}
}
同步方法 变为单线程
用在单例设计模式中,防止出现线程安全问题
将synchronized放在run方法的修饰符中 public synchronized void 锁的是整个方法,等同于单线程
如果修饰的是成员方法 锁对象默认是this对象 如果使用继承thread就锁不住
加锁 --一般不会出现死锁
lock unlock
创建锁对象 Lock lock = new ReentrantLock();
特别注意:先把线程安全问题的代码用try包起来,把lock.unlock()放到finally里中,防止不解锁
wait notify notifyAll
必须写在同步代码块,保证锁对象,其是由锁对象调用,且wait和notify需要用同一锁
public class Patrenaza {
public static void main(String[] args) {
Object o = new Object();
Demo6 demo6 = new Demo6(o);
demo6.start();
Demo7 demo7 = new Demo7(o);
demo7.start();
}
}
class Demo6 extends Thread {
Object o;
public Demo6(Object o) {
this.o = o;
}
public void run() {
synchronized (o) { // 加锁对象
System.out.println("wait------start");
try {
o.wait(); // 用锁对象调用
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait--------end");
}
}
}
class Demo7 extends Thread {
Object o;
public Demo7(Object o) {
this.o = o;
}
public void run() {
synchronized (o) { // 用同一把锁
System.out.println("notiy------start");
o.notify();
System.out.println("notify--------end");
}
}
}
public class Test4Demo {
public static void main(String[] args) {
per p = new per();
new Producer(p).start();
new Consumer(p).start();
}
}
class Producer extends Thread {
per p;
public Producer(per p) {
this.p = p;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
p.set("三", 99);
} else {
p.set("111111111111", 99);
}
}
}
}
class Consumer extends Thread {
per p;
public Consumer(per p) {
this.p = p;
}
public void run() {
for (int i = 0; i < 100; i++) {
p.show();
}
}
}
class per {
private String name;
private int age;
boolean flag;
public per() {
};
public synchronized void set(String name, int age) {
if (!flag) {
this.name = name;
this.age = age;
}
this.flag = true;
this.notify();
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void show() {
if (flag) {
System.out.println(this.name + "==" + this.age);
}
this.flag = false;
this.notify();
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Test3Demo {
public static void main(String[] args) {
List<cat> list = new ArrayList<>();
list.add(new cat("万物", 11));
list.add(new cat("万", 21));
list.add(new cat("物", 51));
Object o = new Object();
new Thread(new prod(o, list)).start();
new Thread(new Consu(o, list)).start();
}
}
class prod implements Runnable {
private Object o;
private List<cat> list;
public prod(Object o, List<cat> list) {
this.o = o;
this.list = list;
}
@Override
public void run() {
while (true) {
synchronized (o) {
if (list.size() == 0) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入名字");
String name = sc.next();
System.out.println("请输入年龄");
int age = sc.nextInt();
list.add(new cat(name, age));
}
o.notify();
try {
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class Consu implements Runnable {
Object o;
List<cat> list;
public Consu(Object o, List<cat> list) {
this.o = o;
this.list = list;
}
@Override
public void run() {
while (true) {
synchronized (o) {
if (list.size() != 0) {
System.out.println(list);
list.remove(0);
}
o.notify();
try {
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class cat {
String name;
int age;
@Override
public String toString() {
return "cat [name=" + name + ", age=" + age + "]";
}
public cat(String name, int age) {
super();
this.name = name;
this.age = age;
}
}
多线程的类,要不就继承Thread 要不就实现Runable接口,都要重写run方法(线程任务) Thread及其子类构建的对象为线程对象
匿名内部类
本质: 实现了接口或者继承了类的子类对象
匿名内部类生成多线程
//开启两个线程,一个打印大写字母表,一个打印小写字母表
public class Jih {
public static void main(String[] args) {
new Thread(){
public void run(){
for(int i = 'a'; i < 'z'; i++){
System.out.println(Thread.currentThread().getName()+(char)i);
}
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {
for(int i = 'A';i<='Z';i++){
System.out.println(Thread.currentThread().getName()+(char)i);
}
}
}).start();
}
}
线程池(Executors类)*************
程序每启动一个线程(start),成本是非常高的(与CPU进行交互);
线程池里的线程结束后,不会马上消失,而是进入空闲状态,等待下一个对象使用
后面再用.start时,考虑能否用pool.execute代替 Executors.new
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Patrenaza {
public static void main(String[] args) {
ExecutorService pool = Executors.newCachedThreadPool(); // 具有缓存功能的线程池:如果没有线程就开启,有了就用;用完先等待,没人用再删
pool.execute(new Runnable() { // 实现多线程的第二种方式的匿名内部类 线程对象
@Override
public void run() { // 线程方法
System.out.println("启动一个线程"); // 线程安全问题不可避免,为防止线程安全,需要同步代码块
// synchronized
}
});
pool.execute(new Thread(new Runnable() { // 匿名内部类
@Override
public void run() { // 线程方法
System.out.println("多线程的第二种方式");
}
}));
pool = Executors.newFixedThreadPool(20); //具有固定线程数的线程池
pool = Executors.newSingleThreadExecutor();//单线程
}
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test2Demo {
public static void main(String[] args) {
ExecutorService pool = Executors.newCachedThreadPool();
//线程池后面的参数可以时实现runable的具体对象,thread也行 runable接口对象也行
pool.execute(new tk()); //两个tk对象,int要加static
pool.execute(new tk());
}
}
class tk implements Runnable {
static int ticket = 100;//必须要加static 因为用线程池匿名内部类
public void run() {
while (true) {
synchronized (this.getClass()) {
if (ticket > 0) {
try {
Thread.sleep(20);
System.out.println(Thread.currentThread().getName() + "========" + ticket--);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
定时器
使用多线程实现的 Thread.sleep();
Timer类 用来执行任务,执行完不会自动关闭
new Timer().schedule (TimerTask task, long delay) TimerTask是个抽象类 重写run方法定义线程任务
new Timer().schedule (TimerTask task, Date time) 如果时间已经超过 就立即执行
new Timer().schedule(TimerTask task, long delay,long period)
new Timer().cancel 放在任务执行语句后面,用于执行完关闭
Date da = new SimpleDateFormat(“yyyy-M-d HH:mm:ss”).parse(“2020-1-8 20:24:20”);
public class Jih {
public static void main(String[] args) throws ParseException {
new Timer().schedule(new TimerTask() {
@Override
public void run() {
System.out.println(new SimpleDateFormat("yyyy-M-d HH:mm:ss").format(new Date()));
}
}, new SimpleDateFormat("yyyy-M-d HH:mm:ss").parse("2020-1-8 20:31:30"),1000);
}
}
用多线程写一个计时器
import java.io.ObjectInputStream.GetField;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimerTask;
import java.util.concurrent.Delayed;
public class Jih {
static boolean flag = true;
public static void main(String[] args) {
get(new TimerTask() {
@Override
public void run() {
System.out.println(new SimpleDateFormat("yyyy/MM/dd HH-mm-ss").format(new Date()));
}
}, 5000, 2000);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cancel();
}
public static void cancel(){
flag = false;
}
public static void get(TimerTask task ,long delay,long period){
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
while(flag){
task.run();
try {
Thread.sleep(period);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}