多线程的部分讲解

多线程:


1.什么是线程
线程是指程序在运行的过程中,能够执行程序代码的一个执行单元.java语言中的线程有四种状态:运行-就绪-挂起-结束.

2.线程与进程的区别.
进程:指一段正在执行的程序.
线程有时也被称之为轻量级的进程,它是程序执行的最小单元.一个进程可以拥有多个线程.各个线程之间共享程序的内存空间(代码段 数据段 堆空间)以及一些进程级的文件(如:打开的文件),但是各个线程拥有自己的栈空间.在操作系统级别上,程序的执行都是以进程为单位的,而每个进程中通常会有多个线程互不影响的并发执行.

3.为什么使用多线程.
    a.提高执行效率,减少程序的响应时间.因为单线程执行的过程只有一个有效的操作序列,如果某个操作很耗时,(或者等待网络响应),此时程序就不会响应鼠标或者键盘的操作,如果使用多线程,就可以将耗时的线程分配到一个单独的线程上执行,从而使程序具备更好的交互性.
    b.与进程相比,线程的创建和切换开销更小.因为开启一个新的进程需要分配一个独立的地址空间,建立许多数据结构来维护代码块等信息,而运行同一个进行的线程开销就很小.同时多线程在数据共享方面效率非常高.
    
    c.市场上的服务器的配置都是CPU或者是多核计算机,具备使用多线程的能力,单个线程使用就无法重复利用计算机资源,造成资源浪费.
    
    d.利用多线程可以简化程序的结构,使程序便于理解和维护.
    
4.同步和异步的区别.
 
 在多线程的环境中,通常会遇到数据共享的问题,为了确保共享资源的正确性和安全性,就必须对共享资源进行同步处理(也就是锁机制).对共享数据进行同步操作(增删改),就必须要获得每个线程对象的锁(this锁),这样可以保证同一时刻只有一个线程对其操作,其他线程要想对其操作需要排队等候并获取锁.当然在等待队列中优先级最高的线程才能获得该锁,从而进入共享代码区.
 java语言在同步机制中提供了语言级的支持,可以通过syschronized关键字来实现同步,但是该方法以很大的开销作为代价,有时候会造成死锁,所以同步机制不是越多越好,要避免所谓的同步控制.
 实现同步的方法有两种:
 第一种:同步方法(this锁)
 第二种:同步代码块,(this锁或者自定义锁)当使用this锁时,就与同步方法共享同一锁,只有当this锁(第一种)释放,第二种才可以使用.同时同步代码块的范围小于同步方法,建议使用,相比之下能够提高性能.
 
 
使用多线程:
1.继承thread类
MyThread.java
public class MyThread extends Thread{
    @Override
    public void run{
        super.run();
        system.out.println("MyThread");
    }
}

Run.java
public class Run{
    public static void main(String [] args){
        MyThread myThread = new MyThread();
        myThread.start();
        system.out.println("运行结束");
    }
}
注:线程是一个子任务,CPU以不确定的方式,或者是以随机时间来调用线程中的run()方法.


2.实现Runnable接口
推荐使用Runable接口,java是单继承多实现.
MyRunnable.java
public class MyRunnable implements Runnable{
    @Override
    public void run{
    Sytem.out.println("MyRunnable");
    }
}

Run.java
public class Run{
    public static void main (String [] args){
    Runnable runnable = new MyRunnable();
    Thread thread =  new Thread(runnable);
    thread.start();
    System.out.println("运行结束!");
    }
}
 

实例变量和线程安全.
定义线程类中的实例变量针对其他线程可以有共享和不共享之分.
第一种:
不共享数据的情况:

MyThread.java
public class MyThread extends Thread{
  private int count = 5;

  public MyThread{
  super();
  this.setName(name);
  }
  
    @Override
    public void run{
        super.run();
        while(count > 0){
        count -- ;
        system.out.println("由"+MyThread.currentThread().getName()+"计算,count="+count);
        }
    }
}

Run.java
public class Run{
    public static void main(String [] args){
        MyThread a = new MyThread("A");
        MyThread b = new MyThread("B");
        MyThread c = new MyThread("C");
        a.start();
        b.start();
        c.start();
    }
}

注:可以看出每一个线程都有属于自己的一个实例变量count,他们之间是互不影响.

第二种:
共享数据的情况:

MyThread.java
public class MyThread extends Thread{
  private int count = 5;

    @Override
    public void run{
        super.run();
        count -- ;
        system.out.println("由"+MyThread.currentThread().getName()+"计算,count="+count);
    }
}

Run.java
public class Run{
    public static void main(String [] args){
        MyThread a = new MyThread("A");
        MyThread b = new MyThread("B");
        MyThread c = new MyThread("C");
        MyThread d = new MyThread("D");
        MyThread e = new MyThread("E");
        a.start();
        b.start();
        c.start();
        d.start();
        e.start();
    }
}

注:
在大多数jvm中,count--操作有三布:
a 取的原有的count值
b 计算i -1
c 对i进行赋值
所以出现多个线程的时候就会出现问题.


解决办法:
使用关键字syschronized关键字.
在run方法之前加上syschronized关键字.

4.一些常用的方法.
4.1 currentThread()
    返回当前正在执行的线程对象的引用
4.2 getId()
    返回此线程的标识符
4.3 getName()
    返回此线程的名字
4.4 getPrority()
    返回此线程的优先级
4.5 isAlive()
    测试这个线程是否处于活动状态
4.6 sleep(long millis)
    使当前正在执行的线程以指定的毫秒数"休眠"(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性.
4.7 interrupt()
    中断这个线程
4.8 isterrupted()和isInterrupted()
    interrupted():测试当前线程是否已经是中断状态,执行后具有状态标志清除为false的功能
    isterrupted():测试线程Thread对相关是否已经是中断状态,但不清楚状态标志.
4.9 setName(String name)
    将此线程的名称更改为等于参数name;
4.10 isDaemon()
    测试这个线程是否是守护线程
4.11 setDaemon(boolean on)
    将此线程标记为daemon线程或者是用户线程

    
4.12 join()
    在很多情况下主线程生成并启动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就需要用到join()方法了.
    
    join的作用:"等待该线程终止",这里需要理解的是主线程等待的是子线程的终止,也就是子线程在调用了join()方法后面的代码,只用等待了子线程结束了才能执行.

4.13 yield()
    作用是放弃当前的CPU资源,将它让给其他的任务去占用CPU时间.
    注意:放弃的事件不确定,可能一会就会重新获得CPU的时间片.
4.14 setProprity(int newProprity)
    更改此线程的优先级
    
5.如果停止一个线程.
stop(),suspend(),resume() 已经被弃用。


5.1 使用interrupt()方法.
    
MyThread.java
public class MyThread extends Thread{
    @Override
    public void run{
        super.run();
        for(int i=0;i<5000;i++){
         system.out .println("i"+(i+1));
        }
    }
}

public class Run{
    public static void main (String [] args){
        try {
        MyThread myThread = new MyThread();
        myThread.start();
        Thread.sleep(2000);
        thread.interrupt();
        }catch(InterruptException exception){
        System.out.println("main catch");
        e.printlnStackTrace();
        }
    }
}

注:线程不会终止。


MyThread.java
public class MyThread extends Thread{
    @Override
    public void run{
        super.run();
        for(int i=0;i<5000;i++){
            if(this.interrupted()){
            system.out.println("已经结束");
            break;
         }
        system.out .println("i"+(i+1));

        }
    }
}

public class Run{
    public static void main (String [] args){
        try {
        MyThread myThread = new MyThread();
        myThread.start();
        Thread.sleep(2000);
        thread.interrupt();
        }catch(InterruptException exception){
        System.out.println("main catch");
        e.printlnStackTrace();
        }
    }
}

for循环虽然已经停止,但是for循环下面的语句还是会执行,说明线程还是未被停止。

5.2 使用return停止线程。

MyThread.java
public class MyThread extends Thread{
    @Override
    public void run{
        while(true){
            if(this.interrupted()){
            System.out.println("停止了");
            return;
            }
            System.out.println("timer="+System.currentTimeMilles());
        }
    }
}

public class Run{
    public static void main (String [] args){
    MyThread myThread = new MyThread();
    myThread.start();
    Thread.sleep(200);
    t.interrupt();
    }
}


6. 线程的优先级。
每个线程都有各自的优先级。线程的优先级可以在程序中表明该线程的重要性。如果有多线程处于就绪状态,系统会根据各自的优先级来决定首先使用哪个线程进入运行状态。 但这个并不表明优先级低的得不到运行,只是运行的几率比较低。
线程的优先级具有继承性,比如A线程启动B线程,A线程的优先级和B线程的优先级是一样的。
线程的优先级具有随机性,线程优先级比较高的并不是每一次都先执行的。

Thread类中包含的成员变量代表了线程的某些优先级。
    Thread.MIN_PROPRITY (常数1),
    Thread.NORM_PROPRITY(常数5),
    Thread.MAX.PROPRITY(常数10)
其中每个线程的优先级都在1-10之间,在默认情况下,线程的优先级都是常数5.


Java多线程的分类:
用户线程:
    运行在前台 执行具体的任务。如程序的主线程,连接网络的子线程等都是用户线程。
守护线程:
    运行在后台 为其他前台线程服务,也可以说守护线程是jvm中非守护线程的佣人。
特点:
    一旦所有的用户线程都结束运行,守护线程会随着jvm一起结束工作。
应用:
    数据库连接池中的检测线程,jvm虚拟机启动后的检测线程。
最常见的守护线程:
    垃圾回收线程


7.2如何设置守护线程

可以通过调用Thread的setDaemon(true)方法设置当前的线程为守护线程.

注意:
    a.setDaemon(true)必须


 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值