快捷键:ALT+enter 创建对象

参数列表·ctr P

查看构造器:ctrl o

一、多线程

1.概念

单线程:就是一条线内能执行的程序

java 怎么单线程cpu过高怎么处理 java单核多线程_构造器

每一份线程有单独的:虚拟机栈 和程序计数器

多个线程共享:方法区和堆 一个进程一份,

2.单核CPU:

只能执行一个线程

多核CPU:

java应用程序java.exe,至少有三个线程:main()主线程,gc()垃圾回收站,异常处理线程

注意:

单核CPU下, 只使用单个线程先后完成多个任务,比多个线程完成用的时间短

3.并行与并发

并行:多个CPU同时执行多个任务,不同人做不同事

并发:一个CPU同时执行多个任务

4.关于线程的8个方法

/**1.Thread.currentThread():静态方法 返回执行当前代码的线程
 * 2.getName():获取当前线程的名字  ①构造器命名public thread(String name){}②通过当前对象命名
 * 3.setName():设置当前线程的名字
 * 4.yield():释放当前执行得线程,给别的线程用
 * 5.join():在线程a中调用线程b的join(),此时线程a进入阻塞状态,直到join()的线程完全执行完以后,线程a才能继续执行
 * 6.stop():过时 强制结束当前线程
 * 7.sleep(long millitime): 让当前线程睡眠指定几毫秒 抛异常
 * 8.isAlive():判断当前线程是否存活

5.线程的调用

时间片

抢占式:高优先级的线程抢占CPU

6.线程的优先级

线程的优先级  不一定实施
 MAX_PRIORITY   优先级10
 NORM_PRIORITY     5
 MIN_PRIORITY      1

创建多线程的方式

一、继承Thread()

  • 当前类继承Thread类
  • 再启动一个线程,必须创建一个新的Thread子类的对象H1,调用此对象的start()
1.创建一个继承于Thread类的子类
 * 2.重写Thread类的run  将此线程执行的内容声明在run()方法中
 * 3.创建Thread类子类的对象  主线程
 * 4.通过此对象调用start()方法
 *
  // 编译100以内的偶数
class  HelloThread extends Thread{   	//1.
    public void run() {					//2.
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
     System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getPriority()+ ":" + i);
            }
        }
    }
    public HelloThread(String name){        //有参构造器 
        super(name);
    }
}


public class ThreadMethodTest {        			   public static void main(String[] args) {     		//分线程  	HelloThread H1=new HelloThread("Thread:1");   //3.方式一 有参构造器
       H1.setPriority(Thread.MAX_PRIORITY);     //最小值10
       H1.start();								//4.
       Thread.currentThread().setName("主线程");  //主线程   Thread.currentThread().setPriority(Thread.MIN_PRIORITY);    // 1
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
        System.out.println(Thread.currentThread().getName()+Thread.currentThread().getPriority()+ ":" + i);
            }
        }
    }
}

二、实现runnable接口

1.创建一个实现了runnable接口的类
2.类去实现runnable接中的抽象方法
3.创建实现类的对象
4.将此对象作为参数传递到Thread类中的构造器中,创建thread类的对象  多态
5.通过thread类的对象调用start()

源码:

class Mthread implements Runnable{   //继承于object
    public void run(){
        for(int i=0;i<100;i++){
            if(i%2==0){
            System.out.println(i);
        }
    }
}
public static class ThreadTest1 {
    public static void main(String[] args) {
        Mthread Mthread1=new Mthread(); //创建当前类的对象
        Thread t1=new Thread( Mthread1);  
//对象作为参数传递到Thread类中的构造器中,创建thread类的对象 多态
        t1.start();
  //②调用了当前线程的run() 调用了private runnable target
    }
  }
}

问题:创建线程,继承和接口如何选择

优先选择实现Runnable接口

继承父类

共享数据

7.线程的生命周期

java 怎么单线程cpu过高怎么处理 java单核多线程_java 怎么单线程cpu过高怎么处理_02

①新建:一个thread类或子类对象被声明创建时,新生的线程对象处于新建的状态

②就绪:新建状态被start()后,进入线程队列等待CPU时间片

③阻塞:被人挂起或执行输入输出操作时,让出CPU并临时中止自己的执行(sleep(long time),join,wait(),suspend() )

④运行:线程被调度,run()方法定义了线程的功能(运行就绪可反复执行)

⑤死亡:完成了全部工作或线程提前强制性中止或出现异常导致结束(执行完run()、stop、Error、Exception)

线程的同步 /线程的安全问题

线程的安全问题:例如,一个线程执行卖票过程中未完成,另一个线程也参与进来,操作卖票

同步机制:

一、同步代码块

  1. 可以继承Thread类
  2. 可以实现Runnable接口

二、同步方法

操作的共享数据的代码完整的声明在一个方法中,我们将此方法声明为同步的

3.也可以继承Thread类

4.也可以实现Runnable接口

在继承下,每个对象都有属性,如果要共享,给属性加上static

static Object obj=new Object();  //设置为静态对象 共用同一把锁

继承Thread类
同步方法的同步监视器 不需要显示的声明
非静态的方法 同步监视器是this
非静态的同步方法:同步监视器是当前类本身

**线程安全问题
 * 一、同步代码块解决Runnable接口线程安全
 * synchronized(同步监视器){
 *     被同步的代码,即操作共享数据的代码
 * }

 * 说明:
 * 共享数据:多个线程共同操作的变量 例如 ticket
 * 同步监视器:即锁 任何一个类的对象都可以充当锁  多个线程共用一把锁!!
 * 相当于单线程
//三个线程共用100张票
//方法一 :同步代码块  解决Runnable接口线程安全
class window1 implements Runnable{
    private int ticket=100;   //三个线程共用100张票
    Person p1=new Person();
    public void run(){
        while(true){
            synchronized (p1){              //包住和ticket相关的代码块
            if(ticket>0){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"卖票"+ticket);
                ticket--;
            }else{
                break;
              }
            }
        }
    }
}
public class WindowTest1 {
    public static void main(String[] args) {
        window1 w1=new window1();
        Thread t1=new Thread(w1);  //多态 父类为thread
        Thread t2=new Thread(w1);
        Thread t3=new Thread(w1);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}
class Person{ }  //定义在其他类

补充:

  • 在实现Runnbale接口时创建多线程的方式中,考虑使用this充当同步监视器
  • 继承Thread类创建多线程,慎用this充当同步监视器,用当前类作为同步监视器
//方法二  同步方法  实现runnbale接口
 操作的共享数据的代码完整的声明在一个方法中,我们将此方法声明为同步的
class window3 implements Runnable{
    private int ticket=100;             //三个线程共用100张票

    public void run(){
        while(true){
                show();
                }
        }
    public synchronized void show(){    
        //同步监视器:this
        if(ticket>0) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println(Thread.currentThread().getName() + "卖票" + ticket);
                ticket--;
            }}}}
public class WindowTest3 {
    public static void main(String[] args) {
        window1 w1=new window1();
        Thread t1=new Thread(w1);               //多态
        Thread t2=new Thread(w1);
        Thread t3=new Thread(w1);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}

三、!Lock锁

JDK5.0新增

  1. *Lock锁:*显示锁手动提供同步(lock()),手动解锁
  2. *synchronized():*隐式锁 自动释放同步监视器
class Window implements Runnable {
    private int ticket=100;
    private ReentrantLock lock=new ReentrantLock(true);   //创建锁对象

    public void run(){
        while(true){
            try{
                lock.lock();  //调用锁定方法
                if(ticket>0){
                    try{
                        Thread.sleep(100);
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
	System.out.println(Thread.currentThread().getName()+"卖票窗口为"+ticket);
                    ticket--;
                }else {
                    break;
                }
            }finally{    //一定会执行的代码
                lock.unlock();  //调用解锁方法
            }
        }
    }
}
public class LockTest {
    public static void main(String[] args) {
        Window w=new Window();

        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();
    }
}

四种方式使用的优先顺序

Lock锁------>同步代码块-------->同步方法(在方法体之外)

10.死锁:

不同线程分别占用对方所需的资源不放手,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁,所有线程处于阻塞状态

一个先A后B 一个先B后A

11.线程的通信:

wait():执行后阻塞,当前线程进入阻塞状态,并释放同步监视器

notify():(唤醒)一旦执行此方法后,就会唤醒优先级高的一个线程,

notifyAll():唤醒所有被wait的线程

三个方法的调用者是同步代码块或同步方法中的同步监视器,否则会出现IllegalMonitorStateException异常

三个方法在Java.lang.Object中

//线程通信   线程1 线程2交替打印 1-100
class Number implements Runnable{
    private int number=1;
    public void run(){
        while(true){
            synchronized(this){                    //同步监视器 任何一个类的对象可以充当
                notify();    					//线程2 唤醒线程1
                if(number<=100){
                    System.out.println(Thread.currentThread().getName()+":"+number);
                    number++;
                    try {
                        wait();               //阻塞一下!抛异常 线程2执行完wait后释放同步监视器
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
public class Communicate {
    public static void main(String[] args) {
        Number n1=new Number();             //创建当前类的对象
        
        Thread t1 = new Thread(n1);//多态 父类给子类
        Thread t2 = new Thread(n1);
        t1.setName("线程1");
        t2.setName("线程2");
        t1.start();
        t2.start();
    }
}
sleep()和wait()的异同

都导致进入阻塞

不同:

  1. 声明位置不同:Thread类中声明sleep(),Object中声明wait()
  2. wait()在同步代码块或同步方法中使用
  3. 是否释放同步监视器 :sleep()不会释放锁 ,wait()会释放锁

三、Callable接口 JDK5.0

如何理解Callable接口与Runnable接口创建线程方式强大

  1. 与run()方法相比,可以有返回值
  2. 方法可以抛出异常,被外面的操作捕获,获取异常类的信息
  3. 支持泛型的返回值
* 实现callable接口   JDK5.0
* 1.创建类实现call方法
* 2.创建接口实现类对象
* 3.将实现类对象的参数传递到FutureTask构造器中,创建FutureTask的对象
* 4.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()
* 5.获取callable中call()的返回值
//    打印出1-100的偶数
class newThread implements Callable {      		//1.创建一个实现Callable接口的类
      public Object  call()  throws Exception{    //回调方法
            int sum=0;                              //装箱
            for(int i=0;i<=100;i++){
                if(i%2==0){
                System.out.println(i);
                sum+=i;
                }
            }
            return sum;
        }
}
public class ThreadNew {
    public static void main(String[] args) {
        newThread newThread = new newThread();     //2.创建callable接口实现类对象
        FutureTask futureTask = new FutureTask(newThread);
         // 泛型 3.将callable接口实现类对象传递到FutureTask构造器中,创建FutureTask对象
        new Thread(futureTask).start();                // FutureTask继承了runnable接口
        //4.将FutureTask的对象作为 参数传递到Thread类的构造器中,并调用start()方法
        try{
            //5.get()返回值即为FutureTask构造器参数 callable实现类重写的call方法的返回值
            Object sum = futureTask.get();             //接收sum值 注意大小写
            System.out.println("总和为"+sum);
        }catch(InterruptedException e){
            e.printStackTrace();
        }catch(ExecutionException e){
            e.printStackTrace();
        }
    }
}

四、线程池

提前创建多个线程,放入线程池中,使用时直接获取,用完放回池中

好处:提高响应速度

降低资源消耗

便于线程管理

corePoolSize:核心池大小

maxmumPoolSize:最大线程数

KeepAliveTime:线程没有任务时最多保持多长时间会终止