java多线程基本概述(九)——ThreadLocal

public interface Lock
Lock implementations provide more extensive locking operations than can be obtained using synchronized methods and statements. //Lock对象提供比同步方法或者同步块更多的灵活性和拓展性,They allow more flexible structuring, may have quite different properties, and may support multiple associated Condition objects.//它们允许更多更灵活的结构,有很多不同的属性,并且支持关联不同的Condition对象
A lock is a tool for controlling access to a shared resource by multiple threads. Commonly, a lock provides exclusive access to a shared resource: //一个Lock对象是一种控制并发访问共享资源的工具。通常,一个Lock对象提供对资源的专有访问:only one thread at a time can acquire the lock and all access to the shared resource requires that the lock be acquired first. 在同一个时间,只能最新持有锁的线程才能访问共享资源However, some locks may allow concurrent access to a shared resource, such as the read lock of a ReadWriteLock.
//然而,一些锁随想允许多个线程同时访问共享资源,比如:ReadWriteLock.
The use of synchronized methods or statements provides access to the implicit monitor lock associated with every object,//同步方法或者同步块提供了对与每个对象相关的隐式锁的访问 but forces all lock acquisition and release to occur in a block-structured way: when multiple locks are acquired they must be released in the opposite order, //但是强制要求锁的获取和释放必须发生在一个块结构中,当要获取多个锁时,它们必须以相反的顺序进行释放。 and all locks must be released in the same lexical scope in which they were acquired.
//且必须在与所有锁被获取时相同的词法范围内释放所有锁
While the scoping mechanism for synchronized methods and statements makes it much easier to program with monitor locks, //虽然 synchronized 方法和语句的范围机制使得使用监视器锁编程方便了很多,and helps avoid many common programming errors involving locks, there are occasions where you need to work with locks in a more flexible way.// 而且还帮助避免了很多涉及到锁的常见编程错误,但有时也需要以更为灵活的方式使用锁。For example, some algorithms for traversing concurrently accessed data structures require the use of "hand-over-hand" or "chain locking": you acquire the lock of node A, then node B, then release A and acquire C, then release B and acquire D and so on. Implementations of the Lock interface enable the use of such techniques by allowing a lock to be acquired and released in different scopes, and allowing multiple locks to be acquired and released in any order.

With this increased flexibility comes additional responsibility. The absence of block-structured locking removes the automatic release of locks that occurs with synchronized methods and statements. In most cases, the following idiom should be used:

     Lock l = ...;
     l.lock();
     try {
         // access the resource protected by this lock
     } finally {
         l.unlock();
     }

When locking and unlocking occur in different scopes, care must be taken to ensure that all code that is executed while the lock is held is protected by try-finally or try-catch to ensure that the lock is released when necessary.
Lock implementations provide additional functionality over the use of synchronized methods and statements by providing a non-blocking attempt to acquire a lock (tryLock()), an attempt to acquire the lock that can be interrupted (lockInterruptibly(), and an attempt to acquire the lock that can timeout (tryLock(long, TimeUnit)).

A Lock class can also provide behavior and semantics that is quite different from that of the implicit monitor lock, such as guaranteed ordering, non-reentrant usage, or deadlock detection. If an implementation provides such specialized semantics then the implementation must document those semantics.

Note that Lock instances are just normal objects and can themselves be used as the target in a synchronized statement. Acquiring the monitor lock of a Lock instance has no specified relationship with invoking any of the lock() methods of that instance. It is recommended that to avoid confusion you never use Lock instances in this way, except within their own implementation.

Except where noted, passing a null value for any parameter will result in a NullPointerException being thrown.

Memory Synchronization

All Lock implementations must enforce the same memory synchronization semantics as provided by the built-in monitor lock, as described in section 17.4 of The Java? Language Specification:

A successful lock operation has the same memory synchronization effects as a successful Lock action.
A successful unlock operation has the same memory synchronization effects as a successful Unlock action.
Unsuccessful locking and unlocking operations, and reentrant locking/unlocking operations, do not require any memory synchronization effects.
Implementation Considerations

The three forms of lock acquisition (interruptible, non-interruptible, and timed) may differ in their performance characteristics, ordering guarantees, or other implementation qualities. Further, the ability to interrupt the ongoing acquisition of a lock may not be available in a given Lock class. Consequently, an implementation is not required to define exactly the same guarantees or semantics for all three forms of lock acquisition, nor is it required to support interruption of an ongoing lock acquisition. An implementation is required to clearly document the semantics and guarantees provided by each of the locking methods. It must also obey the interruption semantics as defined in this interface, to the extent that interruption of lock acquisition is supported: which is either totally, or only on method entry.

As interruption generally implies cancellation, and checks for interruption are often infrequent, an implementation can favor responding to an interrupt over normal method return. This is true even if it can be shown that the interrupt occurred after another action may have unblocked the thread. An implementation should document this behavior.

下面的翻译:

随着灵活性的增加,也带来了更多的责任。不使用块结构锁就失去了使用 synchronized 方法和语句时会出现的锁自动释放功能。在大多数情况下,应该使用以下语句:

     Lock l = ...;
     l.lock();
     try {
         // access the resource protected by this lock
     } finally {
         l.unlock();
     }

锁定和取消锁定出现在不同作用范围中时,必须谨慎地确保保持锁定时所执行的所有代码用 try-finally 或 try-catch 加以保护,以确保在必要时释放锁。
Lock 实现提供了使用 synchronized 方法和语句所没有的其他功能,包括提供了一个非块结构的获取锁尝试 (tryLock())、一个获取可中断锁的尝试 (lockInterruptibly()) 和一个获取超时失效锁的尝试 (tryLock(long, TimeUnit))。

Lock 类还可以提供与隐式监视器锁完全不同的行为和语义,如保证排序、非重入用法或死锁检测。如果某个实现提供了这样特殊的语义,则该实现必须对这些语义加以记录。

注意,Lock 实例只是普通的对象,其本身可以在 synchronized 语句中作为目标使用。获取 Lock 实例的监视器锁与调用该实例的任何 lock() 方法没有特别的关系。为了避免混淆,建议除了在其自身的实现中之外,决不要以这种方式使用 Lock 实例。

除非另有说明,否则为任何参数传递 null 值都将导致抛出 NullPointerException。

内存同步

所有 Lock 实现都必须 实施与内置监视器锁提供的相同内存同步语义,如 The Java Language Specification, Third Edition (17.4 Memory Model) 中所描述的:

成功的 lock 操作与成功的 Lock 操作具有同样的内存同步效应。
成功的 unlock 操作与成功的 Unlock 操作具有同样的内存同步效应。
不成功的锁定与取消锁定操作以及重入锁定/取消锁定操作都不需要任何内存同步效果。
实现注意事项

三种形式的锁获取(可中断、不可中断和定时)在其性能特征、排序保证或其他实现质量上可能会有所不同。而且,对于给定的 Lock 类,可能没有中断正在进行的 锁获取的能力。因此,并不要求实现为所有三种形式的锁获取定义相同的保证或语义,也不要求其支持中断正在进行的锁获取。实现必需清楚地对每个锁定方法所提供的语义和保证进行记录。还必须遵守此接口中定义的中断语义,以便为锁获取中断提供支持:完全支持中断,或仅在进入方法时支持中断。

由于中断通常意味着取消,而通常又很少进行中断检查,因此,相对于普通方法返回而言,实现可能更喜欢响应某个中断。即使出现在另一个操作后的中断可能会释放线程锁时也是如此。实现应记录此行为。

例子:

package soarhu;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class TestNum {
  private Lock lock = new ReentrantLock(true);
    private int a = 1;
  public void test(){
        lock.lock();
      try {
          for (int i = 0; i < 5; i++) {
              System.out.println(Thread.currentThread().getName()+" "+a++);
          }
      } finally {
          lock.unlock();
      }
  }
    public synchronized void test2(){
        try {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName()+" "+a++);
            }
        } finally {
        }
    }
}
public class Test{
    public static void main(String[] args)  {
        TestNum t = new TestNum();
        for (int i = 0; i < 3; i++) {
            new Thread(){
                @Override
                public void run() {
                       t.test();
                      // t.test2();
                }
            }.start();
        }
    }
}

输出结果:test()与test2()实现了相同的效果:

Thread-0 1
Thread-0 2
Thread-0 3
Thread-0 4
Thread-0 5
Thread-1 6
Thread-1 7
Thread-1 8
Thread-1 9
Thread-1 10
Thread-2 11
Thread-2 12
Thread-2 13
Thread-2 14
Thread-2 15

Process finished with exit code 0

关键字synchronized与wait(),notify()/notifyAll()相结合可以实现等待/通知模式。类ReentrantLock也可以实现相同的功能,但须要借助Condition对象。Condition类时JDK5中出现的,它有更好的灵活性,比如可以多路通知功能,也就是一个Lock对象里面可以创建多个Condition(对象监视器)实例,线程对象可以注册在指定的Condition中,从而有选择的通知线程,在线程调度上更加灵活。

   在使用notify()/notifyAll()时,被通知的线程是有JVM随机选择的,但ReentrantLock对象结合Conditon类可以实现前面介绍过的“选择性通知”,这个功能是很重要的。

   而synchronized相当于整个Lock对象中只有一个单一的Condition对象,所有的线程都注册在它的一个对象身上。线程开始notifyAll()时,需要通知所有的WAITING线程,没有选择权,例如:多个wait()的线程和其他notify()的线程都在等待时,那么这些线程可能都会唤醒,而通常我们只是想唤醒处于wait()的等待中的线程。那么Condition就提供了很好的处理。

  

public interface Condition
Condition factors out the Object monitor methods (wait, notify and notifyAll) into distinct objects to give the effect of having multiple wait-sets per object, by combining them with the use of arbitrary Lock implementations. Where a Lock replaces the use of synchronized methods and statements, a Condition replaces the use of the Object monitor methods.
Conditions (also known as condition queues or condition variables) provide a means for one thread to suspend execution (to "wait") until notified by another thread that some state condition may now be true. Because access to this shared state information occurs in different threads, it must be protected, so a lock of some form is associated with the condition. The key property that waiting for a condition provides is that it atomically releases the associated lock and suspends the current thread, just like Object.wait.

A Condition instance is intrinsically bound to a lock. To obtain a Condition instance for a particular Lock instance use its newCondition() method.

As an example, suppose we have a bounded buffer which supports put and take methods. If a take is attempted on an empty buffer, then the thread will block until an item becomes available; if a put is attempted on a full buffer, then the thread will block until a space becomes available. We would like to keep waiting put threads and take threads in separate wait-sets so that we can use the optimization of only notifying a single thread at a time when items or spaces become available in the buffer. This can be achieved using two Condition instances.

 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();
     }
   }
 }

(The ArrayBlockingQueue class provides this functionality, so there is no reason to implement this sample usage class.)
A Condition implementation can provide behavior and semantics that is different from that of the Object monitor methods, such as guaranteed ordering for notifications, or not requiring a lock to be held when performing notifications. If an implementation provides such specialized semantics then the implementation must document those semantics.

Note that Condition instances are just normal objects and can themselves be used as the target in a synchronized statement, and can have their own monitor wait and notification methods invoked. Acquiring the monitor lock of a Condition instance, or using its monitor methods, has no specified relationship with acquiring the Lock associated with that Condition or the use of its waiting and signalling methods. It is recommended that to avoid confusion you never use Condition instances in this way, except perhaps within their own implementation.

Except where noted, passing a null value for any parameter will result in a NullPointerException being thrown.

Implementation Considerations

When waiting upon a Condition, a "spurious wakeup" is permitted to occur, in general, as a concession to the underlying platform semantics. This has little practical impact on most application programs as a Condition should always be waited upon in a loop, testing the state predicate that is being waited for. An implementation is free to remove the possibility of spurious wakeups but it is recommended that applications programmers always assume that they can occur and so always wait in a loop.

The three forms of condition waiting (interruptible, non-interruptible, and timed) may differ in their ease of implementation on some platforms and in their performance characteristics. In particular, it may be difficult to provide these features and maintain specific semantics such as ordering guarantees. Further, the ability to interrupt the actual suspension of the thread may not always be feasible to implement on all platforms.

Consequently, an implementation is not required to define exactly the same guarantees or semantics for all three forms of waiting, nor is it required to support interruption of the actual suspension of the thread.

An implementation is required to clearly document the semantics and guarantees provided by each of the waiting methods, and when an implementation does support interruption of thread suspension then it must obey the interruption semantics as defined in this interface.

As interruption generally implies cancellation, and checks for interruption are often infrequent, an implementation can favor responding to an interrupt over normal method return. This is true even if it can be shown that the interrupt occurred after another action that may have unblocked the thread. An implementation should document this behavior.

翻译内容如下:

Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。

条件(也称为条件队列 或条件变量)为线程提供了一个含义,以便在某个状态条件现在可能为 true 的另一个线程通知它之前,一直挂起该线程(即让其“等待”)。因为访问此共享状态信息发生在不同的线程中,所以它必须受保护,因此要将某种形式的锁与该条件相关联。等待提供一个条件的主要属性是:以原子方式 释放相关的锁,并挂起当前线程,就像 Object.wait 做的那样。

Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例获得 Condition 实例,请使用其 newCondition() 方法。

作为一个示例,假定有一个绑定的缓冲区,它支持 put 和 take 方法。如果试图在空的缓冲区上执行 take 操作,则在某一个项变得可用之前,线程将一直阻塞;如果试图在满的缓冲区上执行 put 操作,则在有空间变得可用之前,线程将一直阻塞。我们喜欢在单独的等待 set 中保存 put 线程和 take 线程,这样就可以在缓冲区中的项或空间变得可用时利用最佳规划,一次只通知一个线程。可以使用两个 Condition 实例来做到这一点。

 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();
     }
   }
 }

(ArrayBlockingQueue 类提供了这项功能,因此没有理由去实现这个示例类。)
Condition 实现可以提供不同于 Object 监视器方法的行为和语义,比如受保证的通知排序,或者在执行通知时不需要保持一个锁。如果某个实现提供了这样特殊的语义,则该实现必须记录这些语义。

注意,Condition 实例只是一些普通的对象,它们自身可以用作 synchronized 语句中的目标,并且可以调用自己的 wait 和 notification 监视器方法。获取 Condition 实例的监视器锁或者使用其监视器方法,与获取和该 Condition 相关的 Lock 或使用其 waiting 和 signalling 方法没有什么特定的关系。为了避免混淆,建议除了在其自身的实现中之外,切勿以这种方式使用 Condition 实例。

除非另行说明,否则为任何参数传递 null 值将导致抛出 NullPointerException。

实现注意事项

在等待 Condition 时,允许发生“虚假唤醒”,这通常作为对基础平台语义的让步。对于大多数应用程序,这带来的实际影响很小,因为 Condition 应该总是在一个循环中被等待,并测试正被等待的状态声明。某个实现可以随意移除可能的虚假唤醒,但建议应用程序程序员总是假定这些虚假唤醒可能发生,因此总是在一个循环中等待。

三种形式的条件等待(可中断、不可中断和超时)在一些平台上的实现以及它们的性能特征可能会有所不同。尤其是它可能很难提供这些特性和维护特定语义,比如排序保证。更进一步地说,中断线程实际挂起的能力在所有平台上并不是总是可行的。

因此,并不要求某个实现为所有三种形式的等待定义完全相同的保证或语义,也不要求其支持中断线程的实际挂起。

要求实现清楚地记录每个等待方法提供的语义和保证,在某个实现不支持中断线程的挂起时,它必须遵从此接口中定义的中断语义。

由于中断通常意味着取消,而又通常很少进行中断检查,因此实现可以先于普通方法的返回来对中断进行响应。即使出现在另一个操作后的中断可能会释放线程锁时也是如此。实现应记录此行为。

例子:

package extthread;

import service.MyService;

public class ThreadA extends Thread {

    private MyService service;

    public ThreadA(MyService service) {
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.await();
    }
}
-------------------------------------------------
package service;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {

    private Lock lock = new ReentrantLock();
    public Condition condition = lock.newCondition();

    public void await() {
        try {
            lock.lock();
            System.out.println(" await时间为" + System.currentTimeMillis());
            condition.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void signal() {
        try {
            lock.lock();
            System.out.println("signal时间为" + System.currentTimeMillis());
            condition.signal();
        } finally {
            lock.unlock();
        }
    }
}
---------------------------------------------------------------------------------
package test;

import service.MyService;
import extthread.ThreadA;

public class Run {

    public static void main(String[] args) throws InterruptedException {

        MyService service = new MyService();

        ThreadA a = new ThreadA(service);
        a.start();

        Thread.sleep(3000);

        service.signal();

    }

}

输出结果:

 await时间为1492527853327
signal时间为1492527856339

wait()等价于awiat,notify()等价于notifyAll()方法

用如果只有一个Condition那么效果和notifyAll()一样,例子:

package test;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

 class ThreadA extends Thread {
    private MyService service;
    public ThreadA(MyService service) {
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.awaitA();
    }
}
 class ThreadB extends Thread {
        private MyService service;
        public ThreadB(MyService service) {
            super();
            this.service = service;
        }
        @Override
        public void run() {
            service.awaitB();
        }
    }

class MyService {

     private Lock lock = new ReentrantLock();
     public Condition condition = lock.newCondition();

     public void awaitA() {
         try {
             lock.lock();
             System.out.println("begin awaitA时间为" + System.currentTimeMillis()
                     + " ThreadName=" + Thread.currentThread().getName());
             condition.await();
             System.out.println("  end awaitA时间为" + System.currentTimeMillis()
                     + " ThreadName=" + Thread.currentThread().getName());
         } catch (InterruptedException e) {
             e.printStackTrace();
         } finally {
             lock.unlock();
         }
     }

     public void awaitB() {
         try {
             lock.lock();
             System.out.println("begin awaitB时间为" + System.currentTimeMillis()
                     + " ThreadName=" + Thread.currentThread().getName());
             condition.await();
             System.out.println("  end awaitB时间为" + System.currentTimeMillis()
                     + " ThreadName=" + Thread.currentThread().getName());
         } catch (InterruptedException e) {
             e.printStackTrace();
         } finally {
             lock.unlock();
         }
     }

     public void signalAll() {
         try {
             lock.lock();
             System.out.println("  signalAll时间为" + System.currentTimeMillis()
                     + " ThreadName=" + Thread.currentThread().getName());
             condition.signalAll();
         } finally {
             lock.unlock();
         }
     }
 }

public class Run {
    public static void main(String[] args) throws InterruptedException {
        MyService service = new MyService();
        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();
        ThreadB b = new ThreadB(service);
        b.setName("B");
        b.start();
        Thread.sleep(3000);
        service.signalAll();

    }

}

输出结果:

begin awaitA时间为1492528283299 ThreadName=A
begin awaitB时间为1492528283300 ThreadName=B
  signalAll时间为1492528286305 ThreadName=main
  end awaitA时间为1492528286305 ThreadName=A
  end awaitB时间为1492528286305 ThreadName=B

可以看到a,b线程同时被唤醒。

package test;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

 class ThreadA extends Thread {
    private MyService service;
    public ThreadA(MyService service) {
        super();
        this.service = service;
    }
    @Override
    public void run() {
        service.awaitA();
    }
}
 class ThreadB extends Thread {
        private MyService service;
        public ThreadB(MyService service) {
            super();
            this.service = service;
        }
        @Override
        public void run() {
            service.awaitB();
        }
    }

class MyService {

     private Lock lock = new ReentrantLock();
     public Condition conditionA = lock.newCondition();
     public Condition conditionB = lock.newCondition();

     public void awaitA() {
         try {
             lock.lock();
             System.out.println("begin awaitA时间为" + System.currentTimeMillis()
                     + " ThreadName=" + Thread.currentThread().getName());
             conditionA.await();
             System.out.println("  end awaitA时间为" + System.currentTimeMillis()
                     + " ThreadName=" + Thread.currentThread().getName());
         } catch (InterruptedException e) {
             e.printStackTrace();
         } finally {
             lock.unlock();
         }
     }

     public void awaitB() {
         try {
             lock.lock();
             System.out.println("begin awaitB时间为" + System.currentTimeMillis()
                     + " ThreadName=" + Thread.currentThread().getName());
             conditionB.await();
             System.out.println("  end awaitB时间为" + System.currentTimeMillis()
                     + " ThreadName=" + Thread.currentThread().getName());
         } catch (InterruptedException e) {
             e.printStackTrace();
         } finally {
             lock.unlock();
         }
     }

     public void signalAll_A() {
         try {
             lock.lock();
             System.out.println("  signalAll时间为" + System.currentTimeMillis()
                     + " ThreadName=" + Thread.currentThread().getName());
             conditionA.signalAll();
         } finally {
             lock.unlock();
         }
     }

     public void signalAll_B() {
         try {
             lock.lock();
             System.out.println("  signalAll时间为" + System.currentTimeMillis()
                     + " ThreadName=" + Thread.currentThread().getName());
             conditionB.signalAll();
         } finally {
             lock.unlock();
         }
     }
 }

public class Run {
    public static void main(String[] args) throws InterruptedException {
        MyService service = new MyService();
        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();
        ThreadB b = new ThreadB(service);
        b.setName("B");
        b.start();
        Thread.sleep(3000);
        service.signalAll_A();

    }

}

输出:等待BCondition释放。一个锁可以有几个监视器。

begin awaitA时间为1492528603637 ThreadName=A
begin awaitB时间为1492528603637 ThreadName=B
  signalAll时间为1492528606640 ThreadName=main
  end awaitA时间为1492528606641 ThreadName=A
时间: 2024-10-26 04:08:35

java多线程基本概述(九)——ThreadLocal的相关文章

“全栈2019”Java多线程第十九章:死锁详解

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多线程第十九章:死锁详解 下一章 "全栈2019"Java多线程第二十章:同步方法产生死锁的例子 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复"Java学习小组&q

Java多线程——&lt;一&gt;概述、定义任务

一.概述 为什么使用线程?从c开始,任何一门高级语言的默认执行顺序是“按照编写的代码的顺序执行”,日常开发过程中写的业务逻辑,但凡不涉及并发的,都是让一个任务顺序执行以确保得到想要的结果.但是,当你的任务需要处理的业务比较多时,且这些业务前后之间没有依赖(比如, a执行的过程中b也可以执行,b没有必要必须等待a执行完毕再去执行),那么此时,我们可以将一个任务拆分成多个小任务. 例如,任务a负责接收键盘的输入,b负责将一些参数及计算提前做好(假设计算量比较大),c负责将a的输入和b的结果做和.此时

java多线程基本概述(九)——Lock(2)

公平锁与非公平锁:公平锁代表获取锁的顺序时按照加入锁的顺序来分配的,即按照FIFO(first in first out)的顺序来的,而非公平锁就时一种抢占式,是随机分配的.不一定先到先地.这就有可能导致某些线程一致获取不到锁. package soarhu; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class TestNum { private Lock l

java多线程基本概述

1.1.概念: 进程:进程是操作系统结构的基础,是一次程序的执行:是一个程序及其数据再处理器上顺序执行时所发生的活动:是程序再一个数据集合上运行的过程,它是系统进行系统资源分配和调度的最小单元. 线程:可以理解为一个程序的不同执行路径,是程序执行流的最小单元.线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源.一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发

java多线程基本概述(六)——简单生产者消费者模式

在线程里,生产者就是生产数据的线程,消费者就是消费数据的线程.在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据.同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者.为了解决这个问题于是引入了生产者和消费者模式.下面实现一个简单的生产者消费者模式: 1.一个消费者一个生产者循环消费生产 package soarhu; import java.util.ArrayList; import java.util.Lis

java多线程基本概述(三)——同步

非线程安全其实是在多个线程对同一个对象实例的变量进行并发访问的时候发生,产生的后果就是脏读,也就是取到的数据是修改过的.而线程安全就是获得的实例变量的值是经过同步处理的,从而不会出现脏读现象. 1.1.1.实例变量非线程安全 如果我们把多个线程并发访问的实例变量转化成方法里面的局部变量,那么就不会产生线程不安全的情况了.因为每个线程拿到的变量都是该线程自己拥有,类似于ThreadLocal类的思想.下面这个例子将变量变为局部变量从而实现线程安全. 1 package soarhu; 2 impo

Java多线程(一)概述及创建

支持多线程是Java语言的特性之一,多线程使程序可以同时存在多个执行片段,根据不同的条件和环境同步或异步工作.线程与进程的实现原理类似,但它们的服务对象不同,进程代表操作系统平台中运行的一个程序,而一个程序中将包含多个线程. 进程: 通常将正在运行的程序成为进程,现在计算机基本都支持多进程操作,比如使用计算机可以边上网,边听音乐,然而计算机上只有一块CPU,实际上,并不能同时运行这些进程,CPU实际上是利用不同时间片段去交替执行每个进程,由于转换速度很快,使人感觉像是在同时运行. 线程: 在一个

java多线程基本概述(二十二)——CountDownLatch(2017-04-20 18:54)

它被用来同步一个或者多个任务,轻质它们等待由其他任务执行的一组操作完成. 你可以向 CountDownLatch 对象设置一个初始计数值,任何在这个对象上调用  await()  的方法都将阻塞,直到这个计数值为0.其他任务在结束其工作时,可以在该对象上调用 countDown() 来减小这个数值,这个方法不会阻塞线程. CountDownLatch 被设计为只触发一次,计数值不能被重置.如果你需要能够重置计数值的版本,则可以使用 CyclicBarrier . CountDownLatch  

java多线程基本概述(七)——join()方法

在很多情况下,主线程创建并启动子线程,如果子线程中有大量的耗时运算,主线程将早于子线程结束,如果想让主线程等待子线程结束后再结束,那么我们可以使用join()方法.调用join()方法的意思是当前线程使调用了该方法的线程执行完成然后再执行自己本身.api文档如下: public final void join(long millis, int nanos) throws InterruptedException Waits at most millis milliseconds plus nan