JAVA--多线程(很重要的呀)

  1. 什么是进程
    概念: 正在运行的程序,所占用的内存的空间资源
  2. 什么是线程
    概述: 线程就是对于CPU的一条独立的执行路径
    看成是一个进程中的,多个小程序的独立执行
  3. 实现多线程的第一种方式
    线程这个事物,也被封装成对象.线程对象的描述类
    java.lang.Thread
    实现创建新线程步骤
    定义类,继承Thread
    重写Thread类run方法
    创建Thread子类对象
    调用的是Thread类的方法start
/*
 *  创建新的执行线程
 *    定义类继承Thread
 *    重写run方法
 *    new Thread子类对象
 *    调用父类方法start()
 *      start 开启线程
 *      JVM调用run
 *  规范,不管让线程运行什么,请把代码写在run中
 */
class SubThread extends Thread{
    public void run(){
        for(int x = 0 ; x < 50 ;x++){
            System.out.println("run.."+x);
        }
    }
}

public class ThreadDemo {
    public static void main(String[] args) {

        SubThread s = new SubThread();
        s.start();
        for(int x = 0 ; x < 50 ;x++){
            System.out.println("main.."+x);
        }
    }
}
  1. 实现多线程第二种方式
    实现接口方式 java.lang.Runnable
    实现步骤
    定义类,实现Runnable接口
    重写抽象方法run
    创建Thread类对象 ,在Thread类的构造方法中,
    传递Runnable接口实现类对象
    调用Thread类方法start

/*创建新的执行线程
*    定义类实现接口Runnable
*    重写run方法
*    new 实现接口类对象
*    创建Thread类对象,传递Runnable实现类
*    调用父类方法start()
*      start 开启线程
*      JVM调用run
*  规范,不管让线程运行什么,请把代码写在run中
*/
public class RunnableDemo {
    public static void main(String[] args) {
        // new 实现接口类对象
        RunnableIterface r = new RunnableIterface();
        //创建Thread类对象,传递Runnable实现类
        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);
        Thread t3 = new Thread(r);
        //调用父类方法start()
        t1.start();
        t2.start();
        t3.start();

    }
}
class RunnableIterface implements Runnable{ //定义类实现接口Runnable
    public void run() {//重写run方法
        System.out.println(Thread.currentThread().getName()+"第二种线程方法~~");     
    }       
}

5 实现线程的两种方式对比
继承Thread
实现Runnable接口
继承Thread,单继承
继承的方式,线程中数据被单个线程独享
实现接口方式,避免了单继承局限性
实现方式,线程中的数据被线程共享
6 同步技术
出现目的,解决线程操作共享数据的安全问题
关键字 synchronized
格式:
synchronized(任意对象){
线程操作的所有共享数据
}
平衡,速度和安全上,保证安全,牺牲速度
任意对象: 监视器 –> 同步锁 – > 锁
线程运行到同步代码块的时候,先判断,判断这个锁还有没有
如果没有,只能等在外面
如果这个所有,有,线程就获取到这个对象锁,进入同步运行
线程出去同步代码块后,对象锁在交还回去
没有锁的线程,不能进入同步执行
上列子~~!

/*
 *  要求:
 *    多线程技术,模拟储户在银行存钱
 *    每次存储100元,分别在两个窗口存,每个窗口存3次
 *    余额是0
 *      存储的时候余额变化
 *        100 200 300 400 500 600
 *    一个是银行  存钱的功能  
 *    一个储户,调用银行的存钱功能,参数
 *    
 *   方法add 代码全是线程共享数据
 *   同步整个方法  synchronized加在方法的声明上
 *   
 *   同步方法,同步函数,同步方法只能被一个线程调用,不调用完成,其他线程不能调用
 *   同步方法有锁吗,肯定有锁 , 本类对象引用 this
 *   
 *   静态同步方法中,肯定也有锁,锁是谁呢,锁必须是对象
 *   对象就是自己类的 class文件 被JVM创建出来的这个对象
 *   
 *   任何一个数据类型 ,JVM都会赋予他一个特别的属性  属性名字 class
 *   静态方法中的同步锁,就是自己本类.class属性
 */
class Bank{
    private static int sum = 0;
    //private Object obj = new Object();
    public static synchronized void add(int money){
        //synchronized(Bank.class){
        sum = sum + money;
        System.out.println(sum);
        //}
    }
}

class Customer implements Runnable{
    private Bank b = new Bank();
    public void run(){
        for(int x = 0 ; x < 3 ; x++){
            b.add(100);
        }
    }
}

public class ThreadDemo9 {
    public static void main(String[] args) {
        Customer c = new Customer();
        Thread t0 = new Thread(c);
        Thread t1 = new Thread(c);
        t0.start();
        t1.start();
    }
}
  1. 死锁
    多个线程,抢夺同一个对象锁,造成程序假死现象
/*
 *   多线程,争夺同一个对象锁资源,出现的假死
 *   同步的嵌套技术实现
 */
//定义类,实现同步的嵌套
class Dead implements Runnable{
    private boolean b;
    Dead(boolean b){this.b=b;}
    public void run(){
        while(true){
            //对变量b进行判断,如果b=true,同步嵌套
            //线程先进入同步A锁,在进入同步B锁
            if(b){
                synchronized(LockA.locka){
                    System.out.println("if...locka");
                    synchronized(LockB.lockb){
                        System.out.println("if...lockb");
                    }
                }
            }
            //变量的值b=false,同步嵌套
            //线程先进入同步B锁,在进同步A锁
            else{
                synchronized(LockB.lockb){
                    System.out.println("else...lockb");
                    synchronized(LockA.locka){
                        System.out.println("else...locka");
                    }
                }
            }
        }
    }
}


public class ThreadDead {
    public static void main(String[] args) {
        Dead d1 = new Dead(true);
        Dead d2 = new Dead(false);
        Thread t1 = new Thread(d1);
        Thread t2 = new Thread(d2);
        t1.start();
        t2.start();
    }
}

//创建2个类,2个类的对象,作为锁使用
class LockA{
    public static final LockA locka = new LockA();
}
class LockB{
    public static final LockB lockb = new LockB();
}
  1. 线程通信
    所有的线程,操作的共享数据,必须都同步
    必须保证所有的同步使用的锁,唯一的
    线程通信中的等待与唤醒机制
    生产者生产完成后,需要等待,等待之前唤醒消费者线程
    消费者线程打印完后,需要等待,等待之前唤醒生产者线程

    程序加了线程的等待和唤醒 Object类的方法 wait notify
    抛出 IllegalMonitorStateException异常
    无效的监视器状态异常
    wait notify 必须有锁的支持
    只有锁对象才能调用


/*
 * 线程的通信
 *   多线程针对同一个学生资源,采用不同类型的数据操作
 *   一个线程,负责对学生资源的复制,另一个线程对学生资源负责打印值
 */
//定义学生类,资源对象,姓名,姓别成员即可
class Student  {
    String name;
    String sex;
    boolean flag ;
}
//定义生产者线程,负责对学生赋值
class Product implements Runnable{
    private Student s ;
    Product(Student s){this.s=s;}
    public void run(){
        int x = 0 ;
        while(true){
         synchronized(s){
            //判断标记 
            if(s.flag){
                try{s.wait();}catch(Exception ex){}
            }
            if(x%2==0){
                s.name = "张三";
                s.sex = "男";
            }else{
                s.name = "李四";
                s.sex = "女";
            }
            x++;
            //修改标记的值
            s.flag = true;
            //唤醒消费线程
            s.notify();
         }
        }
    }
}
//定义消费者线程,负责学生变成获取值
class Customer implements Runnable{
    private Student s; 
    Customer(Student s){this.s=s;};
    public void run(){
        while(true){
          synchronized(s){  
            //判断标记
            if(!s.flag){
             try{s.wait();}catch(Exception ex){}
            }
            System.out.println(s.name+"..."+s.sex);
            //修改变量的值
            s.flag=false;
            //唤醒生产线程
            s.notify();
          }
        }
    }
}

public class ThreadDemo {
    public static void main(String[] args) {
        Student s = new Student();
        //创建2个Runnable接口实现类
        Product p = new Product(s);
        Customer c = new Customer(s);
        Thread t0 = new Thread(p);
        Thread t1 = new Thread(c);
        t0.start();
        t1.start();
    }
}

这个线程通信中包含了一个唤醒等待机制

  1. 线程中的一些小知识点(别小看哦)
    为什么wait(),notify(),notifyAll()等方法都定义在Object类中
    操作线程的,Thread,为什么不写在Thread类中,出现在Object类中
    锁的问题,锁是任意对象,等待还是唤醒必须有锁的支持,只有锁对象才能调用
    方法写了最顶层的父类中,任何子类对象,当作锁,都可以调用线程的方法了
    Thread类方法sleep 和 Object方法wait有什么区别
    sleep 不会释放对象锁
    wait 释放对象锁,被唤醒,从新获取锁才能运行

    1. 线程池
      池技术 pool
      有些操作,非常耗时好资源
      创建新的线程
      JAVA连接数据库服务器
      程序开始的时候,创建出锁需要的线程,创建只有1次
      容器中保存起来,从容器取出,运行完成后,线程不死,继续回到容器中等待
      集合容器
      ArrayList
      add(t0);
      add(t0);
      add(t0);
      Thread t =array. remove(0);
      t.start();
      add(t);
      JDK5版本,添加使用线程池的功能,内置线程池的概念
      工厂类, 负责创建需要的对象
      Executors 类负责创建线程池的对象
      全部都是静态方法,类名调用
      static ExecutorService newCachedThreadPool() 创建新的线程池对象
      返回的肯定是接口ExecutorService实现类的对象

    static ExecutorService newFixedThreadPool(int nThreads) 创建新的线程池对象,传递int参数
    线程池就有指定的线程个数

    static ExecutorService newSingleThreadExecutor() 创建线程池对象,池子里面只有1个线程
    等同于newFixedThreadPool(1)

    ExecutorService 接口方法
    submit(Runnable task) 用于执行线程池中的线程,线程去运行Runnable接口实现类的run方法
    void run(){
    }
    Future 获取线程执行后的返回值

    Future
    submit(Callable task) 用于执行线程池中的线程,运行的是Callable接口的实现类的方法

/*
 * 使用JDK5新特性,创建线程池,并且让线程运行起来 
 *   1. 使用Executors静态方法创建线程池对象
 *   2. ExecutorService接口方法 submit执行线程
 *   submit(Runnable)
 *  
 */


class RunnableImpl implements Runnable{
    public void run(){
        System.out.println(Thread.currentThread().getName());
    }
}
public class ThreadPoolDemo {
    public static void main(String[] args) {
        //使用Executors静态方法创建线程池对象,2个线程的池子
        ExecutorService es = Executors.newFixedThreadPool(2);
        //调用接口方法submit 传递Runnable接口实现类
        es.submit(new RunnableImpl());
        es.submit(new RunnableImpl());

        //关闭线程池
        es.shutdown();
    }
}
  1. 实现线程的第三种方式
    java.util.concurrent.Callable
    实现Callable接口,重写call方法
    call可以有返回值,可以抛出异常
    第三种方式,出现的版本1.5
    不要和Thread,Runnable,Callable只能作用在线程池里

    Future submit(Callable call)传递Callable接口实现类的对象
    submit方法执行完毕后,可以获取到线程运行后的返回值
    返回的是Future接口的实现类对象

    Future接口方法 get 可以获取到线程执行后的返回值结果

/*
 * 实现线程的第三种方式,结合线程池使用
 * 线程运行后的结果
 */

//定义类,实现Callable,重写call方法
class CallableImpl implements Callable<String>{
     public String call()throws Exception{
         System.out.println("执行了call方法");
         return "abc";
     }
}


public class ThreadPoolDemo1 {
    public static void main(String[] args)throws Exception {
        //Executors  静态方法创建线程池
        ExecutorService es = Executors.newFixedThreadPool(1);
        //ExecutorService方法submit运行线程
        //submit方法,返回Future接口实现类对象
        Future<String> f = es.submit(new CallableImpl());
        String s = f.get();
        System.out.println(s);

        es.shutdown();
    }
}
  1. 单例设计模式Single
    实现思想: 保证一个类的对象,在内存中唯一性
    这个是个很有趣的东西~~!

先来个饿汉式的~~!

/*
 * 保证Single类,的对象在内存中是唯一性
 *   私有构造方法
 *     创建对象,是要调用构造方法
 *   本类成员位置,创建自己类的对象
 *   提供公共访问方式,外类获取对象
 *   
 * 以下写法,成为单例模式 -- 饿汉式
 *   
 */
public class Single {

    private Single(){}
    private static Single s = new Single();

    public static Single getInstance(){
        return s;
    }
}

再来个懒汉的~~!

/*
 * 保证Single类的对象,在内存中的唯一性
 *   懒汉式,对象的延迟加载
 *  利用同步保证数据安全,利用双重if判断,提升程序的执行效率
 */
public class Single {
    private Single() {
    }
    private static Single s = null;
    public static  Single getInstance() {

        if (s == null) {
            synchronized (Single.class) {
                if (s == null)//这个if是绝对绝对不可以去掉
                    s = new Single();
            }
        }
        return s;
    }
}

然后就是一下线程的方法~~!
* Thread类的方法 setDaemon(boolean )true
* 线程标记为守护线程,必须在start之前使用
* 所有的线程,都是守护线程的时候JVM,就退出
*
* Thread类的方法 static yield 线程的让步
* * 等待该线程终止
*
* Thread类 join
* 执行join方法的线程,会一次性执行完毕
* 其他线程,等我执行完后,抢CPU资源

 * 线程的控制方法

* Thread类的静态的方法sleep(long 毫秒值)
* 让执行的线程,在指定的毫秒内,休眠,时间到了,自己醒来继续执行
这个方法要自己try —catch ~~

线程的优先级
* 每个线程都有自己的优先级 1-10
* Thread类方法 int getPriority() 获取线程的优先级
* 优先级高,在用CPU的时间相对更多一些
*
* setPriority(int newPriority) 设置线程的优先级
* Thread类中,提供三个静态成员变量,说明优先级

  • 如何获取,设置线程的名字

    • 每个线程都有自己的名字
    • Thread-0 -1 -2

      • 获取线程名字
    • Thread类方法 String getName()
    • 在Thread类用,在Thread子类使用

      • Thread类,有一个静态方法 currentThread()
    • 返回当前正在运行的线程对象 Thread currentThread()
    • 继续使用线程对象,调用getName方法获取名字

      • 设置线程名字
    • Thread类的方法 void setName(String name)设置线程名字
    • Thread类的构造方法(String name)

    • JDK5新特性,实现线程的加锁和释放锁

    • java.util.concurrent.locks
    • 接口Lock 实现类ReentrantLock
    • 替代了同步代码块,同步方法的使用
    • 接口方法: lock 获取锁 unlock释放锁

    终止线程的2个方式

    • 第一个方式 stop 过时
    • 第二个方式 结束run就可以

      • void interrupt() 中断线程
    • 比喻:
    • 线程 ->wait永久等待,没有任何线程唤醒你
    • interrupt让等待线程停止

class Stop implements Runnable{
    private boolean flag = true;

    public void run(){
        while(flag){
            synchronized(this){
                try{this.wait();}
                catch(Exception ex){
                    ex.printStackTrace();
                    System.out.println("抓住异常");
                    flag = false;
                }
            System.out.println("run...");
            }
        }
    }

    public void setFlag(boolean flag){
        this.flag =flag;
    }
}

public class ThreadStop {
    public static void main(String[] args)throws Exception {
         Stop s = new Stop();
         Thread t0 = new Thread(s);
         t0.start();
         Thread.sleep(5);
         t0.interrupt();
        // s.setFlag(false);
    }
}

以上方法不分顺序~
还有线程池 线程组
!
*Thread类的方法 ThreadGroup getThreadGroup()
*获取线程组对象,返回值是ThreadGroup类的对象
*ThreadGroup类方法 String getName()组的名字
*
*ThreadGroup对线程进行分组管理
* 分组管理一起对一个组中的线程进行统一的设置
*
*ThreadGroup构造方法 传递字符串的组的名字
* 可以自己定义组名,传递给ThreadGroup类构造方法
*
*如何把线程放在线程组中
*Thread类构造方法 第一个参数传递的是线程组的对象
*第二个参数,传递的Runnable接口的实现类对象

  • 使用JDK5新特性,创建线程池,并且让线程运行起来
    1. 使用Executors静态方法创建线程池对象
    1. ExecutorService接口方法 submit执行线程
  • submit(Runnable)

线程这个只是点实在是太乱了~~总结的不好 多多包涵

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值