Java 线程(Thread)

Java 线程

一、程序,进程,线程

1)程序,进程,线程

程序

为完成特定的功能,使用计算机语言编写的一系列的指定集合,即静态代码

进程

进行中的程序,被加载到内存中,是操作系统分配资源的最小单位

线程

是进程中的最小的执行单元(任务),是操作系统进行任务调度的最小单元,隶属于进程。、

线程和进程的关系

1.一个线程只能属于一个进程,线程不能脱离进程

2.一个进程中至少有一个线程(主线程),java中的main()方法就是用来启动主线程

3.在主线程中可以创建并启动其他的线程

4.一个进程内的所有线程共享该进程的内存资源

二、创建线程

1)继承Thread 类的方式

Thread 类是java 提供的对线程进行管理的类

package com.xytx.javathread.threadtest1;

public class MyThread extends Thread{
    //继承Thread 类
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("线程:"+i);
        }
    }
}

package com.xytx.javathread.threadtest1;

public class Test {
    public static void main(String[] args) {
        System.out.println("main:开始");
        //创建线程对象
        MyThread myThread = new MyThread();
        //myThread.run();  调用run(),不能启动线程,就是普通的方法调用
        myThread.start();//启动线程

        for (int i = 0; i < 1000; i++) {
            System.out.println("main:"+i);
        }
        System.out.println("main结束");

    }
}

2)实现Runnable 接口的方式

package com.xytx.javathread.threadtest2;

public class Test {
    public static void main(String[] args) {
        //创建一个线程要执行的任务
        PrintNum printNum = new PrintNum();
        //创建线程
        Thread thread = new Thread(printNum);
        thread.start();
        Thread thread1 = new Thread(printNum);
        thread1.start();
    }
}

package com.xytx.javathread.threadtest2;

public class PrintNum implements Runnable{
    //实现Runnable 接口
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

三、Thread 方法

Thread 方法

package com.xytx.javathread.threadway;

public class ThreadWay {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread();
        thread.run();//线程任务执行的方法
        thread.start();//启动线程
        //Thread(target) 创建线程,并指定任务
        //Thread(target,name) 创建线程,并指定任务,定义线程名称
        Thread.currentThread();//获取到当前所在的线程
        thread.getName();// setName() 获取线程的名称
        thread.getPriority();//获得优先级
        thread.setPriority(1);//设置优先级
        /*
        设置线程优先级
        线程优先级默认是5,最大是10,最小是1
        设置优先级后,不一定优先级高的,每一次都是有限执行,需要操作系统调用
        */
        /*
        重写run();方法中出现异常,不能抛出,必须处理
         */
        Thread.sleep(1000);//让线程休眠指定时间(单位)
        Thread.yield();//线程让步,主动让步  主动让出CPU执行权 可以直接进入到就绪队列中
        thread.join();//等待该线程结束


    }
}

守护线程 setDaemo

必须在启动线程之前设置守护线程,否则会出现异常:

IllegalThreadStateException 异常

当其他用户线程结束后,守护线程自动结束

如:垃圾回收器

四、 多线程

1)多线程

多线程:一个应用程序内部,可以同时执行多个任务

2)多线程优点

(1)提高程序处理能力,响应速度提高

(2)提高CPU利用率,压榨硬件的价值

(3)提升程序结构,将复杂任务分为多个线程,独立运行

3)多线程缺点

(1)对内存,CPU要求提高了,提升硬件性能改善

(2)多线程对同一个共享资源进行访问

(3)多线程需要协调和管理,所以需要CPU跟踪线程

4)线程同步

并发与并行

(1)并发:在同一个时间节点上,多个事情同时执行

(2)并行:在一个时间段内,多个事情依次执行

5)线程安全问题

多线程 + 访问同一个资源

6)解决办法

解决办法:排队+锁
模拟售票

  • 继承Thread实现
/*
售票的线程
 */
public class TicketThread extends Thread{
          static int num = 10;//票数  共享资源
          static Object obj = new Object();//保证只有一个
    @Override
    public void run() {
        while(true){
            if(num>0){
               print();
            }else{
                break;
            }
        }
    }
    /*
      synchronized(同步监视器)在修饰方法时,同步对象(锁), 默认是this  一旦创建多个线程对象(只针对继承Thread类的方式)
      static修饰后,同步对象变为 线程类(类只有一个)
     */
    public static synchronized void print(){
          if(num>0){
              try {
                  Thread.sleep(1000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              System.out.println(Thread.currentThread().getName()+"售出票:"+num);//0
              //线程1再减之前   0
              num--;
          }
    }
      /*  @Override
        public void run() {
           while(true){
               //synchronized(同步锁,就是一个对象,但是要求对象只有一个)
               synchronized(obj){
                   if(num>0){
                       try {
                           Thread.sleep(1000);
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                       System.out.println(Thread.currentThread().getName()+"售出票:"+num);//0
                       //线程1再减之前   0
                       num--;
                   }else{
                       break;
                   }
               }//同步代码块,执行完成后 同步对象(锁) 会自动释放
           }
        }*/
}

public class Test {

    public static void main(String[] args) {
        TicketThread t1 = new TicketThread();
                     t1.setName("窗口1");

        TicketThread t2 = new TicketThread();
                     t2.setName("窗口2");

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

  • Runnable实现
public class TicketThread  implements  Runnable{
       int num = 10;//共享变量

    @Override
    public void run() {
        while(true){
                if(num>0){
                    print();
                }else{
                    break;
                }
        }
    }

    //synchronized 默认同步锁对象是this
    public synchronized void print(){
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if(num>0){
            System.out.println(Thread.currentThread().getName()+":"+num);
             num--;
         }
    }

   /* @Override
    public void run() {
            while(true){
                //添加同步对象,这种方式可以使用this来表示锁对象
                synchronized (this){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if(num>0){
                        System.out.println(Thread.currentThread().getName()+":"+num);
                        num--;
                    }else{
                        break;
                    }
                }
            }
    }*/
}

public class Test {
    public static void main(String[] args) {
        //创建出票任务
        TicketThread ticketThread = new TicketThread();
        
        //两个线程执行一个任务  num是只有一个的
        Thread t1 = new Thread(ticketThread,"窗口1");
        Thread t2 = new Thread(ticketThread,"窗口2");
              t1.start();
              t2.start();
    }
}

五,Lock锁

  • 从JDK 5.0开始,Java提供了更强大的线程同步机制-通过显式定义同步锁对象来实现同步。同步锁使用Lock对象充当。
  • java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。
  • ReentrantLock类实现了Lock,它拥有与synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显式加 锁、释放锁。
public class TicketThread  implements  Runnable{

       int num = 10;//共享变量
       Lock lock = new ReentrantLock();

    @Override
    public void run() {
        while(true){
                if(num>0){
                    print();
                }else{
                    break;
                }
        }
    }

    public void print(){
        //System.out.println("ssss");
        try {
            lock.lock();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(num>0){
                System.out.println(Thread.currentThread().getName()+":"+num);
                num--;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();//在finally中释放 锁
        }
        //System.out.println("ssssssssssss");
    }
}

public class Test {
    public static void main(String[] args) {
        //创建出票任务
        TicketThread ticketThread = new TicketThread();
        //两个线程执行一个任务  num是只有一个的
        Thread t1 = new Thread(ticketThread,"窗口1");
        Thread t2 = new Thread(ticketThread,"窗口2");
              t1.start();
              t2.start();
    }
}

六,线程死锁

  • 不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步 资源,就形成了线程的死锁出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续。
  • 设计时考虑清楚锁的顺序,尽量减少嵌套的加锁交互数量。
public class DieLock extends  Thread{

    static Object objA = new Object();
    static Object objB = new Object();
     boolean  flag;
    public DieLock(boolean flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
          if(flag){//线程1
              synchronized (objA){
                  System.out.println("ifObjA");
                  synchronized (objB){
                      System.out.println("ifObjB");
                  }
              }
          }else{//线程2
             synchronized (objB){
                 System.out.println("elseBbjB");
                 synchronized (objA){
                     System.out.println("elseObjA");
                 }
             }
          }
    }
}

public class Test {
    public static void main(String[] args) {
        DieLock dieLock1 = new DieLock(true);
        DieLock dieLock2 = new DieLock(false);
        dieLock1.start();
        dieLock2.start();
    }
}

七,线程通信

  • 线程通信指的是对个线程通过消息传递实现相互牵制,相互调度,即线程间的相互作用。
  • 设计三个方法:
    ​ .wait() 一旦执行此方法,当前线程就进入了阻塞状态,并释放同步监视器
    ​ .notify() 一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的那个
    ​ .notifuAll() 一旦执行此方法,就会唤醒所有被wait的线程
  • 说明:
    .wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中。
    .wait(),notify(),notifyAll()三个方法是定义在java.lang
    .Object类中。
    案例:消费者问题
/*
    柜台 只有一个
 */
public class Counter {
       int  num = 0;

       /*
         添加
        */
     // 同步对象时this  就是同一个Counter对象
     public synchronized void add(){
           if(num==0){
               num++;
               System.out.println("生产者线程生产了一个商品");
               this.notify();//唤醒消费者
           }else{
               try {
                   this.wait();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
     }


       /*
         取
        */
     public synchronized void sub(){
         if(num>0){
             num--;
             System.out.println("消费者线程消费了一个商品");
             this.notify();
         }else{
             try {
                 this.wait();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
     }
}

/*
  消费者线程
 */
public class CustomerThread extends  Thread{

     Counter counter;

    public CustomerThread(Counter counter) {
        this.counter = counter;
    }

    @Override
    public void run() {
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            counter.sub();
        }
    }
}


/*
   生产者
 */
public class ProductorThread extends Thread{

    Counter counter;

    public ProductorThread(Counter counter) {
        this.counter = counter;
    }

    @Override
    public void run() {
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            counter.add();
        }
    }


public class Test {
    public static void main(String[] args) {
        Counter c = new Counter();//两个线程共享的资源  柜台
        ProductorThread p = new ProductorThread(c);
        CustomerThread cu = new CustomerThread(c);
                 p.start();
                 cu.start();
    }
}


八,新增创建线程方式(Callable)

  • 实现Callable接口与使用Runnable相比,Callable功能更强大些.
  • 相比run()方法,可以有返回值
  • 方法可以抛出异常
  • 支持泛型的返回值
  • 需要借助FutureTask类,获取返回结果
public class MyThread  implements Callable<Integer> {

    /*
        可以有返回值,可以泛型定义
        可以抛出异常
     */
    @Override
    public Integer call() throws Exception {
            int num = 0;
            num = 10;
            for (int i = 0; i <10 ; i++) {
                  num+=i;
            }
        return num;
    }
}

public class Test {

    public static void main(String[] args) {
        MyThread myThread  = new MyThread();

        FutureTask<Integer> futureTask = new FutureTask(myThread);//添加
        Thread t = new Thread(futureTask);
                t.start();

        try {
            Integer res =     futureTask.get();
            System.out.println(res);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值