Java高级编程之多线程

1.程序、进程、线程的理解

        程序:是为完成特定任务,用某种语言编写的一组指令的集合,即一段静态的代码,静态对象(个人理解:程序是一段代码的集合,程序是“死”的,因为它并没有被加载到内存中)

        进程:是程序的一次执行过程,或是正在运行的一个程序,是一个动态的过程,有它自身的产生、存在、消亡过程-----生命周期(个人理解:被加载到内存中的程序成为了进程,即运行中的程序)

        线程:进程可进一步细化为线程,是一个程序的一条内部执行路径(个人理解:一个进程中可以有一个或多个线程,其代表不同的功能)

           

2.并行与并发

        并行:多个cpu同时执行多个任务,如不同的人做不同的事(错误理解:并行是针对单核而言(即一个cpu),他会给人一种假象--让你认为它会同时执行多个线程,实际上对于并行而言,cpu会给他们分配时间片,时间片一到就要切换到下一个线程)

        并发:一个cpu(采用时间片)同时执行多个任务。如秒杀、多个人做同一件事(错误理解:并发是针对多核而言(即多个cpu),不同的cpu同时执行不同的线程即为并发)

3.创建多线程的两种方式

        3.1 继承Thread类

package com.atguigu.java;



class MyThread extends Thread{
    @Override
    public void run() {
       for(int i = 0;i < 100; i++){
           if(i % 2 == 0){
               System.out.println(Thread.currentThread().getName()+i);

           }


       }
    }
}

public class ThreadTest {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
        MyThread myThread1 = new MyThread();
        myThread1.start();

        for (int i = 0; i < 100; i++) {
            if (i % 2 != 0) {
                System.out.println(Thread.currentThread().getName()+ i);

            }
        }
        System.out.println("main线程输出");
    }
}

        注意:

                我们启动一个线程必须调用start方法而不能用继承类的对象调用run方法

                如果再启动一个线程,必须再创建该继承类的对象,然后调用start方法 

        详细步骤:

                        1.继承Thread类

                        2.重写run方法

                        3.创建该实现类的对象

                        4.调用start方法

                start方法说明:一经调用start方法就意味着两件事--1.启动了该线程  2.调用了该线程中的run方法 

        3.2 实现Runnable接口

package com.atguigu.java;
// 1.采用同步方法解决线程安全的问题
class  Window2 implements Runnable{
    private int ticket = 100;

    @Override
    public void run() {
        while (true){

                show();

            }


    }
    public synchronized void show(){


        if(ticket > 0){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"正在售卖:"+ticket+"票");
            ticket--;
        }

    }
}



public class WindowTest1 {
    public static void main(String[] args) {
        Window2 window = new Window2();
        Thread thread = new Thread(window);
        Thread thread1 = new Thread(window);
        Thread thread2 = new Thread(window);
        thread.start();
        thread1.start();
        thread2.start();



    }
}

        详细步骤:

                        1.创建实现Runnable接口的实现类

                        2.重写Runnable中的run方法

                        3.创建该实现类的对象

                        4.创建Thread类的对象,并将实现类的对象作为参数传递到Thread类构造器中

                        5.调用start方法

               两种实现方式的对比:优先选用实现Runnable接口的方式

                                                        1.实现的方式没有单继承的局限性

                                                        2.实现的方式更适合用来处理数据共享的问题

                                       

        

4.Thread类的常用方法

package com.atguigu.java;

class MyThread2 extends Thread{
    @Override
    public void run() {
        for(int i = 0;i < 100;i++){
            if(i % 2 == 0) {
//                try {
//                    sleep(10);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
                System.out.println(Thread.currentThread().getName() + ":" + i);

            }


        }
    }
}


public class ThreadTest1 {
    public static void main(String[] args) {
        MyThread2 myThread2 = new MyThread2();
        myThread2.setName("分线程");
        myThread2.setPriority(Thread.MAX_PRIORITY);
        myThread2.start();
        Thread.currentThread().setName("主线程");
        Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
        for(int i = 0;i < 100;i++){
            if(i % 2 != 0)
            System.out.println(Thread.currentThread().getName()+":"+i);
            

        }

    }




}

        

5.Thread的生命周期

        

 

6.线程的同步机制

        同步代码块:

package com.atguigu.java;
// 1.使用同步代码块解决线程安全的问题
// 需要注意的问题:多个线程要共用同一把锁,任何一个类都可以用来创建一把锁
class  Window implements Runnable{
    private int ticket = 100;
    Object object = new Object();
    @Override
    public void run() {
        while (true){
          synchronized(object){

              if(ticket > 0){
                  try {
                      Thread.sleep(100);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  System.out.println(Thread.currentThread().getName()+"正在售卖:"+ticket+"票");
                  ticket--;
              }
              else {
                  break;
              }
          }

        }
    }
}



public class WindowTest {
    public static void main(String[] args) {
        Window window = new Window();
        Thread thread = new Thread(window);
        Thread thread1 = new Thread(window);
        Thread thread2 = new Thread(window);
        thread.start();
        thread1.start();
        thread2.start();



    }
}

                注意:在使用同步代码块时需要注意同步监视器和共享变量

                        同步监视器:形象的来说,它就是一把锁,这把锁可以是任何一个类的对象,多个线程要共用这把锁,不能每个线程都有属于自己的一把锁,否则仍然会导致线程安全问题。

                        共享变量:多个线程都可以访问的变量称为共享变量

        同步方法:

package com.atguigu.java;
// 1.采用同步方法解决线程安全的问题
class  Window2 implements Runnable{
    private int ticket = 100;

    @Override
    public void run() {
        while (true){

                show();

            }


    }
    public synchronized void show(){


        if(ticket > 0){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"正在售卖:"+ticket+"票");
            ticket--;
        }

    }
}



public class WindowTest1 {
    public static void main(String[] args) {
        Window2 window = new Window2();
        Thread thread = new Thread(window);
        Thread thread1 = new Thread(window);
        Thread thread2 = new Thread(window);
        thread.start();
        thread1.start();
        thread2.start();



    }
}

        

        Lock类:

package com.atguigu.java;

import java.util.concurrent.locks.ReentrantLock;

// 1.使用同步代码块解决线程安全的问题
// 需要注意的问题:多个线程要共用同一把锁,任何一个类都可以用来创建一把锁
class  Window4 implements Runnable{
    private int ticket = 100;
    ReentrantLock reentrantLock = new ReentrantLock();

    @Override
    public void run() {
        while (true){

                reentrantLock.lock();
            try {
                if(ticket > 0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"正在售卖:"+ticket+"票");
                    ticket--;
                }
                else {
                    break;
                }
            } finally {
                reentrantLock.unlock();
            }



        }
    }
}



public class LockTest1 {
    public static void main(String[] args) {
        Window4 window = new Window4();
        Thread thread = new Thread(window);
        Thread thread1 = new Thread(window);
        Thread thread2 = new Thread(window);
        thread.start();
        thread1.start();
        thread2.start();



    }
}

        同步机制的优点:可以解决线程不安全的问题

                             缺点:每次执行就相当于单线程执行的过程,效率低下 

                

7.线程通信

        需要用到的三个方法:wait()、notify()、notifyAll()

package com.atguigu.java;

class  Communication implements Runnable{
    private int number = 1;

    @Override
    public void run() {
       while (true){
           synchronized (this){
               notify();
               if(number <= 100){
                   System.out.println(Thread.currentThread().getName()+":输出的数字为:"+number);
                   number++;
               }else {
                   break;
               }
               try {
                   wait();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }


       }
    }
}


public class  CommunicationTest{
    public static void main(String[] args) {
        Communication communication = new Communication();
        Thread thread = new Thread(communication);
        Thread thread1 = new Thread(communication);
        thread.start();
        thread1.start();

    }


}

        需要注意的是三个方法de调用者要是同一个同步监视器(即同一把锁)否则编译不通过

8.JDK5.0新增线程的创建方式

        实现Callable接口

package com.atguigu.java;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

class MyCallable implements Callable<Integer>{


    @Override
    public Integer 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 CallableTest {
    public static void main(String[] args) {
        MyCallable myCallable = new MyCallable();
        FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
        new Thread(futureTask).start();
        try {
            Integer integer = futureTask.get();
            System.out.println(integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }


    }



}

                

        线程池

package com.atguigu.java;


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

class  MyPool implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i <100 ; i++) {
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName()+i);
            }
        }
    }
}
public class ThreadPoolTest {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        System.out.println(executorService.getClass());
        ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor)executorService;
        threadPoolExecutor.setCorePoolSize(16);



        MyPool myPool = new MyPool();
        executorService.execute(myPool);
        executorService.shutdown();

    }


}

                继承Thread类,实现Runnable接口,实现Callable接口,线程池这四种方法在开发中一般选用线程池的方法。

        线程池的优点:

                1.提高反应时间

               2. 降低资源消耗

9.关于多线程的几个高频面试题

        sleep和wait方法的异同:

  异:      1.所处的类不同,sleep在Thread类中,而wait在Object中

                2.使用的范围不同,sleep可以在任何地方使用,而wait只能在同步代码块或同步方法中使用

                3.sleep方法使用后,不会释放同步监视器,而wait会释放同步监视器

 同:        都能使当前线程阻塞

        synchronized和lock的异同:

异:        synchronized在执行完相应的同步代码块以后,会自动释放同步监视器,而lock需要手动开启同步(lock),结束同步时也需要手动结束(unlock)。

同:        都能解决线程安全问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值