多线程技术

多线程技术

1、什么是进程,什么是线程
	进程是一个应用程序(一个软件)		
	线程是一个进程中的执行场景/执行单元		一个进程可以同时启动多个线程	

2、在java中,多线程共享堆内存和方法区内存的内容,但是栈内存独立,一个线程一个栈

​ 假设启动10个线程,会有10个栈空间,每个栈和每个栈之间互不干扰,各自执行各自的,这就是多线程并发,可以提高效率

3、在java中,实现线程有三种方式

​ (1)编写一个类,直接继承java.lang.Thread

/*
实现线程的第一种方式
    编写一个类,直接继承java.lang.Thread,重写run()方法
    怎么创建线程对性,怎么启动线程?
 */
public class ThreadTest1 {
    public static void main(String[] args) {
        //这里是main方法,这里的代码属于主线程
        //新建一个分支线程对象
        MyThread myThread = new MyThread();
        //启动线程
        myThread.start();
        /*start方法的作用启动一个分支线程,在jvm中开辟一个新的栈空间,这段代码完成之后,瞬间就结束了
          这段代码的任务只是为了开辟一个新的栈空间,只要新的栈空间开辟出来,start方法就结束了
          启动成功的线程会自动调用run方法,并且run方法在分支栈的底部(压栈)(它和mian是平级的)。
          如果不写启动程序,直接写 myThread run()方法,并没有起到多线程的作用,还是在一个线程中运行的
         */
        //接下来的代码还是运行在主线程中
    }
}
class MyThread extends Thread{
    @Override
    public void run() {
        //  在这里编写程序,这段程序运行在分支栈中
        //这里的run可以简单的想象为主程序里的main
        System.out.println("这段程序运行在分支栈中");
    }
}

​ (2)编写一个类实现java.lang.Runnable接口,比较常用(面向接口编程)

public class ThreadTest2 {
    public static void main(String[] args) {
        //创建一个可运行的对象
        MyRunnable r = new MyRunnable();
        //将可运行的对象封装成一个线程对象
        Thread t = new Thread(r);
        //启动线程
        t.start();
    }
}
//这并不是一个线程类,是一个可运行的类,它还不是一个线程
class MyRunnable implements  Runnable{
    @Override
    public void run() {
    }
}

​ (3)实现Collable接口(JDK 8新特性)

​ 这种方式实现的线程可以获取线程的返回值。

public class ThreadTest10 {
    public static void main(String[] args) {
        //创建一个“未来任务类对象”
        FutureTask task = new FutureTask(new Callable() {
            @Override
            public Object call() throws Exception {//call方法相当于run方法,只不过有返回值
                Thread.sleep(10000);
                return new Object();
            }
        });
        //创建线程对象
        Thread t = new Thread(task);
        //启动线程
        t.start();
        //在主线程中 如何获取t线程的返回值结果?
        Object o = task.get();
        //get方法的执行,会导致当前线程阻塞
    }
}
4.、线程的三个常用方法
    如何获取当前线程对象
      thread currentThread = thread.currentThread();这是一个静态方法,
      获取线程对象的名字,修改
      m.getName()
      m.setName("mmm");
5、线程的sleep方法
    static void sleep(long millis)这是一个静态的方法,单位是毫秒
    Thread.sleep(1000)  作用:让当前线程计入休眠状态,
    也可与以用于间隔特定的时间再执行其它的代码
注意它是一个静态的方法,就算你用引用去调用它,那他执行时也是执行Thread.sleep(1000),最后也只会在当前线程中起作用。
如何唤醒一个正在睡眠的线程
	public static void main(String[] args) {
        Runnable target;
        Thread m = new Thread(new MyRunnerable2());
        m.setName("mmm");
        m.start();
        //希望m线程5秒钟后醒来
        try {
            Thread.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //打断线程的睡眠。这里利用的异常的处理,程序显示异常,然后代码执行完毕
        m.interrupt();
    }
}
class MyRunnerable2 implements Runnable{
    @Override
    public void run() {
        System.out.println("睡眠开始");
        try {//睡的时间长一点
            Thread.sleep(1000*60*60);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("睡眠结束");
    }
6、在java中如何强行终止一个线程?
  public static void main(String[] args) throws InterruptedException {       
      MyRunnerable4 m = new MyRunnerable4();                                 
      Thread t = new Thread(m);                                              
      t.setName("ttt");                                                      
      t.start();                                                             
      Thread.sleep(1000*5);                                                  
      m.run = false;                                                         
      //你想什么时候终止t的执行,那你就把标记run改为false就结束了                               
      //t.stop();//已过时                                                       
      //缺点:容易丢失数据                                                            
  }                                                                                
class MyRunnerable4 implements  Runnable{                                      
  //打印一个boolean标记                                                            
  Boolean run = true;                                                        
  @Override                                                                  
  public void run() {                                                        
      for(int i =0 ;i <10 ;i++){                                             
          if(run) {                                                          
              System.out.println(Thread.currentThread().getName() + i);      
              try {                                                          
                  Thread.sleep(1000 * 5);                                    
              } catch (InterruptedException e) {                             
                  e.printStackTrace();                                       
              }                                                              
          }else{//终止当前线程                                                     
              return;                                                        
          }                                                                  
      }                                                                      
  }                                                                          
7、关于多线程并发环境下,数据的安全性问题(重要)
1、什么时候数据在多线程并发的环境下会存在安全问题
三个条件:	1、多线程并发
		   2、有共享数据
		   3、共享数控有修改行为
2、如何解决

​ 线程排队执行,不能并发,这种机制被称为线程同步机制,线程同步就是线程排队了,线程排队了就会牺牲一部分效率。安全第一,效率第二

​ 涉及到两个专业术语

异步编程模型:线程t1,t2各自执行各自的,谁也不需要等谁,这种编程模型就是多线程并发

同步编程模型:就是t1和t2各自执行的时候必须相互等待对方执行完毕,这就是排队

锁的概念
/*在java语言中,任何对象都有一把锁(这其实是一个标记)
以下代码执行原理,假设t1和t2线程并发,若t1先执行了遇到synchronized,这个时候会自动找“后面共享对象”的对象锁
找到之后,并占有这把锁,然后执行同步代码块中的程序。直到同步代码块代码结束,这把锁才汇释放。直到t1释放了,t2才会执行

这就达到了线程排队执行
这里需要注意:()中的共享对象一定要选好了。这个共享对象一定是你需要排队执行的这些线程对象所共享
 */
线程同步机制的语法:
synchronized的语法:
	第一种:同步代码块 synchronized(){
						同步代码块
    				}
    第二种:在实例方法上使用synchronized
    		表示同步对象一定是this,并且同步代码块是整个方法体
   
   第三种:在静态方法上使用synchronized
    		表示找类锁,类锁永远只有一把,就算创建100个对象,也只有一把
    		对象锁是一个对象一把,类锁是100个对象也可能只是1把锁
3、死锁的概念(面试可能会叫你写)
public class DeadLocked {
    public static void main(String[] args) {
        Object o1 = new Object();
        Object o2 = new Object();
        Thread t1 = new MyThread1(o1,o2);
        Thread t2= new MyThread3(o1,o2);
        t1.start();
        t2.start();
    }
}
class MyThread1 extends Thread {
    Object o1;
    Object o2;
    public MyThread1(Object o1, Object o2) {
        this.o1 = o1;
        this.o2 = o2;
    }
    @Override
    public void run(){
        synchronized (o1){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (o2){

            }
        }
    }
}
class MyThread3 extends Thread{
    Object o1;
    Object o2;
    public MyThread3(Object o1, Object o2) {
        this.o1 = o1;
        this.o2 = o2;
    }
    @Override
    public void run(){
        synchronized (o2){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (o1){

            }
        }
    }
}
4、以后开发中如何解决线程同步问题

​ 1、尽量使用局部变量代替 实例变量 和 静态变量

​ 2、如果必须是实例变量,可以考虑创建多个对象,这样实例变量的内存就不共享了

​ 3、以上两种都不行的话,选择 synchronized

5、守护线程

​ 特点:一般守护线程是一个死循环,所有的用户线程结束,守护线程就自动结束

用在什么地方呢?

6、定时器

​ 作用:间隔特定的时间执行特定的程序

7、关于Object类中的 wait 方法和 notify 方法(生产者和消费者模式)
  1. wait 和 notify 方法不是线程对象的方法,java中的任何一个对象都有,因为是Object自带的

  2. 他们不是通过线程对象去调用的

  3. wait()方法作用:Object o = new Object();

    ​ o.wait(); 表示正在o对象上活动的线程进入无期限等待状态,直到被唤醒为止

    ​ o.notify();可以让正在o对象上等待的线程被唤醒

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值