zoukankan      html  css  js  c++  java
  • java_多线程

    1,多线程概念及相关对象。

    2,线程同步

    3,Lock类

    4,多线程其他方法

    1.1多线程概念

    1.1.1进程;是一个正在执行中的程序。每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元

    1.1.2线程:就是进程中的一个独立的控制单元。线程在控制着进程的执行。

    1.1.3多线程即,多个线程共同执行一段代码,已达到提高效率,比如,一个浏览器必须能同时下载多个图片;一个Web服务器必须能同时响应多个用户请求;等都需要使用多线程技术来完成。

    1.1.4java已经提供了对线程这类事物的描述。就是thread类。

    1.2多线程的创建

    1.2.1创建线程的第一种方式:继承Thread类。
    步骤:
    1,定义类继承Thread类
    2,复写Thread类中的run方法。
    目的:将自定义的代码存储在run方法中,让线程运行。
    3,调用线程的start方法,
    该方法两个作用:启动线程,调用run方法。

    问:为什么要覆盖run方法呢?

            答:Thread类用于描述线程,该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run方法。
    也就是说Thread类中的run方法,用于存储线程要运行的代码。(Thread类里的run()方法的方法体是空的,所以想要执行自己指定的代码就得覆盖父类的run()方法

    1.2.2创建线程的第二种方式:实现Runable接口 

    步骤:
    1,定义类实现Runnable接口
    2,覆盖Runnable接口中的run方法。
    将线程要运行的代码存放在该run方法中。
    3,通过Thread类建立线程对象。
    4,将Runnable接口中的子类对象作为实际参数传递给Thread类的构造函数。
    为什么要将Runnable接口的子类对象传递给Thread的构造函数
    因为自定义的run方法所属的对象是Runnable接口的子类对象。
    所以要让线程去执行指定对象的run方法。就必须明确该run方法所属的对象。)
    5,调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。

    1.2.3 两种方式的对比:

    1,采用实现Runnable接口的方式创建多线程

    ->线程类只是实现了Runnable接口,还可以继承其他类。

    ->在这种方式下,多个线程共享一个Runnable子类对象,所以非常适合多个相同线程来吹同一份资源的情况。

    ->劣势是:如果需要访问当前线程,则必须使用Thread.currentThread()方法。

    2,采用继承Thread类的方式

    ->因为线程类已经继承了Thread类,所以不能再继承其他类父类。

    ->如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。

    2.1线程安全问题

    2.1.1 引发安全问题的原因

    当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分还没有执行完,
    另一个线程参与进来执行。导致了共享数据的错误。

    2.2线程同步问题

    2.2.1 同步代码块

    JAVA对于多线程的安全问题提供了专业的解决方式。
    同步代码块。
    synchronized(obj)
    {
    需要被同步的代码。//哪些代码需要同步?看哪些语句在操作共享数据。
    }
    obj如同锁(监视器)。持有锁的线程可以在同步中执行。
    没有持有锁的线程即使夺取了cpu的执行权,也进不去。因为没有获取锁

    obj的选定

    虽然java程序允许使用任何对象作为同步监视器,但想一下同步监视器的目的:阻止两个线程对同一个共享资源进行并发访问,

    因此通常使用可能被并发访问的共享资源充当同步监视器。


    2.2.2同步方法

    与同步代码块对应,java的多线程安全支持还提供了同步方法,同步方法就是使用synchronized关键字来修饰某个方法,则该方法称为同步方法。

    对于同步方法而言,无须显式指定同步监视器,同步方法的同步监视器是this,也就是该对象本身。

    静态的同步方法,使用的锁是该方法所在类的字节码文件对象。类名.class


    2.2.3同步的前提

    1,必须有两个或者两个以上的线程。(两个人以上才锁门)
    2,必须是多个线程使用同一个锁。

    如果加了同步还出现安全问题就要考虑到两个前提是否都满足。

    2.2.4死锁

    一个同步里面嵌套一个同步。锁不一样。

    死锁例子:

    class Test implements Runnable
    {
    	private boolean flag;
    	Test(boolean flag)
    	{
    		this.flag = flag;
    
    	}
    	public void run()
    	{
    		if(flag)
    		{
    			synchronized(MyLock.locka)
    			{
    				System.out.println("if locka");
    				synchronized(MyLock.lockb)
    				{
    					System.out.println("if lockb");
    				}
    			}
    		}
    		else
    		{
    			synchronized(MyLock.lockb)
    			{
    				System.out.println("else lockb");
    				synchronized(MyLock.locka)
    				{
    					System.out.println("else locka");
    				}
    			}
    		}
    		
    	}
    }
    class MyLock
    {
    	static Object locka = new Object();
    	static Object lockb = new Object(); 
    }
    class DeadLockTest
    {
    	public static void main(String[] args) 
    	{
    		Thread t1 = new Thread(new Test(true));
    		Thread t2 = new Thread(new Test(false));
    		t1.start();
    		t2.start();
    	}
    }
    2.3线程通信

    多个线程在操作同一个资源,(一个线程在存,一个线程在取),想要存一个打印一个。

    为了实现这个功能,可以借助于Object类提供的wait(),notify()和notifyAll()3个方法,这3个方法并不属于Thread类,而是属于Object类,但是这三个方法必须由同步监视器对象来调用。

    问:为什么这些操作线程的方法要定义在Object的类中呢?

    答:因为这3个方法需要同步监视器对象来调用,而同步监视器对象可以是任意对象。

    2.3.1wait()

    导致当前线程等待,直到其他线程调用该不同监视器的notify()或notifyAll()方法来唤醒该线程。

    调用wait()方法的当前线程会释放对该同步监视器的锁。

    2.3.2notify()

    唤醒在此同步监视器上等待的单个线程。

    2.3.3notifyAll()

    唤醒在此同步监视器上等待的所有线程。

    当多个线程进行存,多个进行进行取时,避免程序最后被阻塞无法继续向下执行。可以使用notifyAll()

    但是notifyAll()方法是将所有等待线程唤醒,可不可只唤醒对方线程呢?


    3.1Lock类

    将同步Synchronized(隐视加锁,解锁) 替换成实现Lock操作(显示加锁,解锁)
    ( Lock实现提供了比使用synchronized方法和语句可获得的更广泛的锁定操作)
    lock():获取锁。
    unLock()释放锁。

    3.2Condition类

    如果程序不使用synchronized关键字来保证同步,而是直接使用Lock对象来保证同步,则系统不存在隐式的同步监视器,也就不能使用wait(),notify(),notifyAll()方法进行线程通信。

    所以在使用Lock对象时,java提供了一个Condition类来保持协调

    Condition实例被绑定在一个Lock对象上,要获得特定Lock实例的Condition实例,调用Lock对象的newCondition()方法即可,

    Condition替代了同步监视器的功能。Condition提供了3个方法await(),signal(),aignalAll()来替换wait()wait(),notify(),notifyAll().

    具体使用方法见:

    class BoundedBuffer {
       final Lock lock = new ReentrantLock();
       final Condition notFull  = lock.newCondition(); 
       final Condition notEmpty = lock.newCondition(); 
    
       final Object[] items = new Object[100];
       int putptr, takeptr, count;
    
       public void put(Object x) throws InterruptedException {
         lock.lock();
         try {
           while (count == items.length) 
             notFull.await();
           items[putptr] = x; 
           if (++putptr == items.length) putptr = 0;
           ++count;
           notEmpty.signal();
         } finally {
           lock.unlock();
         }
       }
    
       public Object take() throws InterruptedException {
         lock.lock();
         try {
           while (count == 0) 
             notEmpty.await();
           Object x = items[takeptr]; 
           if (++takeptr == items.length) takeptr = 0;
           --count;
           notFull.signal();
           return x;
         } finally {
           lock.unlock();
         }
       } 
     }

    4.1停止线程

    stop方法已经过时。

    suspend:会发生死锁

    问:如何停止线程?
    答:只有一种,run方法结束。开启多线程运行,运行代码通常都是循环结构。
    只要控制循环,就可以让run方法结束,也就是线程结束。

    但是。当线程处于冻结作态,就不会读取到标记,那么线程就不会结束。

    所以,当没有指定的方式让冻结的线程回复到运行状态时,这时需要对冻结进行清除,
    强制让线程恢复到运行状态中来,这样可以操作标记让线程结束。

    Thread类提供该方法 interrupt();会产生InterruptedException.

    1,定义循环结束标记
    因为线程运行代码一般都是循环,只要控制了循环即可。
    2,使用interrupt(中断)方法(不正常唤醒,会发生异常)
    该方法是结束线程的冻结状态(wait,sleep),使线程回到运行状态中来

    4.2后台线程

    有一种线程,它是在后台运行的,它的任务是为其他的线程提供服务,这种线程被称为“后台线程”,又称为守护线程。JVM的垃圾回收线程就是典型的后台线程。

    后台线程有一个特性:如果所有的前台线程都死亡,后台线程会自动死亡。

    调用Thread对象的setDaemon(true)方法可将指定线程设置成后台线程。

    setDaemon(true)必须在start()方法之前调用,否则会引发illegalThreadStateException异常。

    4.3join线

    Thread提供了让一个线程等待另一个线程完成的方法--join()方法。当在某个程序执行流中调用其他线程的join()方法时,调用线程将被阻塞,直到被join方法加入的join线程执行完为止。

    用法:join()方法通常由使用线程的程序调用,以将大问题划分成许多小问题,每一个小问题分配一个线程。当所有的小问题都得到处理后,再调用主线程来进一步操作。

    4.4线程让步:yield

    yield()方法是一个和sleep()方法有点相似的方法,它也是Thread类提供的一个静态方法,它也可以让当前正在执行的线程暂停,但他不会阻塞该线程,它只是将该线程转入就绪状态。yield()只是让当前的线程暂停一下,让系统的线程调度器重新调度一次,完全可能的情况是:当某个线程调用了yield()方法暂停之后,线程调度器又将其调度出来重新执行。

    4.4改变线程优先级

    Thread提供了setPriority()方法来设置指定线程的优先级,其中参数可以是一个整数,1-10.也可以使用Thread类的如下3个静态常量。

    ->MAX_PRIORITY  10

    ->MIN_PRIORITY  1

    ->NORM_PRIORITY  5




  • 相关阅读:
    PHP:使用Zend对源码加密、Zend Guard安装以及Zend Guard Run-time support missing的解决方法
    PHP:WampServer下如何安装多个版本的PHP、mysql、apache
    Windows7下无法打开chm(mk:@MSITStore:路径[cannot open the file mk@MSITstore:路径]),chm索引就关闭的解决办法
    C#:ListView控件如何实现点击列表头进行排序?
    C#:struct的陷阱:无法修改“xxx”的返回值,因为它不是变量
    C#:装箱和拆箱相关知识整理
    wifipineapple的evilportal
    mshta 反弹shell
    kali系统教程:创建热点
    office漏洞利用--获取shell
  • 原文地址:https://www.cnblogs.com/grkbeyond/p/4147267.html
Copyright © 2011-2022 走看看