Java多线程-同步

我们的多线程环境,在不同的(不可预测的)调度顺序之下,线程争相运行,走走停停,这是一种异步状态。

而同步,虽然叫做同步,但其实是一个一个挨着执行,所以是一种串行。

而由于多个线程对于状态的异步访问可能导致安全问题。

比如:

if(   朋友A不在图书馆  ) {

------------------------------------------- A来到图书馆

        去宿舍找A

}

再比如单例:

if( instance == null) {

                     ------------------------------------  切换到另一个线程,另一个线程创建了一个实例

              ...new instance;

}


我们不难发现,由于线程的切换,会导致我们不希望被打断的操作出现错误。

这就是我理解的原子性,原子性指的是不可分割,那么我们不希望被打断的(操作不可能被打断,意味着不会切换线程,当前线程对这个原子操作要么就执行完,要么就一点都不执行)

比如:

i++

这个操作在Java中不是原子的,它的执行过程是,先读出i,然后加1,然后写入i

假设在读出之后,写回之前,另一个线程也读取了,那么就可能出现错误。因为如果这是一个计数器,那么就会少记一次

再比如,要得到偶数

i++

--------------------------另一个线程来了

i++

就会得到奇数。

所以,我们的程序要注意,哪些地方是必须要保证一致的,不可变的,需要保证原子操作的,根据定义和功能的不同一定要尽可能仔细。

所以,安全性被被破坏很多时候就是在一个线程应该独占操作的一段区间内,有别的操作插入进来执行了。

所以,我们只能想办法来保证这个县城==线程独占一段操作,即同步。(即将这段操作变为原子的——不可打断的)

__________________________________________________________________________________________________________________________


同步主要实现有synchronized   volatile  显示锁  原子变量等

synchronized:


比如:

public synchronized int add(){

    return i++;

}

synchronized 关键字有两种用法:synchronized 方法         synchronized 块

方法开始执行,线程就就独占该锁,直到从该方法返回时释放,被阻塞的线程才可以获得锁,进入方法执行。确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可运行状态,从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为 synchronized)

除了类实例,每一个类也对应一把锁,我们也可以将类的静态成员函数声明为 synchronized ,以控制其对类的静态成 员变量的访问。


每个Java对象都可以用作一个视线同步的锁,这些所被称为内置锁。所以当一个线程获取某个对象的锁的时候,其他线程无法获取所有同一个对象的锁(看作是同一个锁)

但是! 可以重入同一个锁,即在一个对象的锁内,可以访问同一个对象的锁的另外的同步代码块

线程进入同步代码块的时候自动获得锁,退出的时候,自动释放锁。

对于同步代码块仍然有:

1 当两个并发线程访问synchronized(obj)同步代码块时,一个时间内只能有一个线程得到执行。另一个线 程必须等待当前线程执行完这个代码块以后才能执行该代码块。

2 当一个线程访问synchronized(obj)同步代码块时,另一个线程仍然可以访问该obj非synchronized 同步代码块。

3 当一个线程访问synchronized(obj)同步代码块时,其他线程对object中所有其它synchronized 同步代码块的访问将被阻塞。 


________________________________________________________________________________________________________________________________


volatile:
这是一种稍弱的同步机制,注意,不是说i的声明加上volatile,那么在i++的时候就不会被打断了,它不会执行加锁操作。而应该是用来维护可见性。一个变量随时可能被放在看不见的缓存,所以,这个关键字最大的作用是在读取volatile变量的时候保证是最新的值。

Java的内存机制允许编译器和处理器对操作进行重排序,而且缓存数据。而volatile就会提醒编译器,编译器不会对这个变量的相关操作和其他操作重排序,而且不会放入缓存。、

因为比如

while(     条件  )

     中断


当条件变量更新的时候可能是不可见的,无法捕捉到,所以可以声明为volatile。


—————————————————————————————————————————————————————————————————————————————

原子变量

当有多个线程同时执行这些类的实例包含的方法时,具有排他性,即当某个线程进入方法,执行其中的指令时,不会被其他线程打断,而别的线程就像自旋锁一样,一直等到该方法执行完成,才由JVM从等待队列中选择一个另一个线程进入,这只是一种逻辑上的理解。实际上是借助硬件的相关指令来实现的,不会阻塞线程


比如:AtomicLong  i   =  new  AtomicLong( 0 );

           count.incrementAndGet();

这个递增操作就被同步了(不能被打断了)




### 回答1: 您好!如果我理解正确的话,您的问题是关于JMU Java 07多线程同步访问的。以下是我的回答: 多线程编程是指在一个程序中同时执行多个线程的编程技术。多线程编程在提高程序性能、增强程序交互性等方面有很大的优势,但也会引入一些问题,比如线程安全问题。 当多个线程同时访问共享资源时,可能会出现线程不安全的问题,比如数据竞争、死锁等。为了避免这些问题,我们需要使用同步机制来确保线程安全。 Java中提供了多种同步机制,比如synchronized关键字、ReentrantLock类、Semaphore类等。这些同步机制都可以用来保证多线程访问共享资源的安全性。 其中,synchronized是最常用的同步机制之一。在Java中,synchronized关键字可以用来修饰方法或代码块,以实现同步访问共享资源。synchronized可以保证在同一时间只有一个线程可以访问共享资源,从而避免了数据竞争等线程安全问题。 除了synchronized之外,Java还提供了一些其他的同步机制,比如ReentrantLock类和Semaphore类。ReentrantLock类提供了比synchronized更灵活的锁机制,可以实现可重入锁、公平锁等功能。Semaphore类可以控制同时访问共享资源的线程数量,从而避免资源被过度占用的问题。 总的来说,多线程编程是一项复杂而重要的技术,需要仔细研究和实践。在实际开发中,我们需要根据具体的需求选择合适的同步机制来确保多线程访问共享资源的安全性。 ### 回答2: 多线程编程是在当前计算机领域中最为常见的技术之一,它可以利用计算机中的多核处理器来使程序运行更加高效。但是,多线程编程中可能会出现的最大问题就是线程安全,因为线程之间可能会访问相同的资源,从而导致竞态条件。 在Java中,可以通过使用synchronized关键字来实现同步访问,从而避免线程安全问题。synchronized关键字可以用于两种不同的情形:同步方法和同步块。在同步方法中,方法是同步的,即每个线程在执行该方法时都需要获取该对象的锁,如果该锁已经被其他线程获取,则需要等待直到此锁被释放。在同步块中,需要手动指定锁,即每个线程在执行同步块时需要获取该指定锁,其他线程如果需要访问该代码块中的共享资源也需要获取该指定锁,这样就保证了该代码块中的所有共享资源的同步访问。 除了synchronized关键字外,Java还提供了其他一些同步机制来实现线程安全,如ReentrantLock类和CountDownLatch类等。ReentrantLock类可以实现更为灵活的同步访问控制,但需要手动释放锁;而CountDownLatch类则用于同步一个或多个线程,使这些线程在某个条件满足之前一直处于等待状态。 在进行多线程编程时,应该尽量避免对同步访问造成瓶颈,应该通过减小同步代码块的范围等方式来提高程序的效率。此外,多线程编程时还应该进行线程安全性的测试,以确保程序能够正确地运行。 ### 回答3: 在Java中,多线程是一种非常常见的编程方式。由于多线程的特点,对共享资源的访问会出现竞争的情况,这种竞争可能会导致数据不一致或程序异常等问题。因此,在多线程编程中,我们需要采取一些措施来保证共享资源的访问能够正确、有序地进行,这就是同步机制。 同步机制包括两种方式:锁和信号量。锁是最基本的同步机制。锁有两种类型:互斥锁(Mutex)和读写锁(ReadWriteLock)。互斥锁用于保护共享资源,保证同一时间只有一个线程可以访问它,其他线程需要等待锁释放后才能继续访问。读写锁用于读写分离场景,提高了多线程访问共享资源的并发性。读写锁支持多个线程同时读取共享资源,但只允许一个线程写入共享资源。 信号量是一种更加高级的同步机制。信号量可以用来控制并发线程数和限制访问共享资源的最大数量。在Java中,Semaphore类提供了信号量的实现。Semaphore可以控制的线程数量可以是任意的,线程可以一起执行,也可以分批执行。 除了锁和信号量,Java还提供了一些其他同步机制,比如阻塞队列、Condition等。阻塞队列是一种特殊的队列,它支持线程在插入或者删除元素时阻塞等待。Condition是一种锁的增强,它可以让线程在某个特定条件下等待或者唤醒。 在多线程编程中,使用同步机制需要注意以下几点。首先,同步机制要尽可能的保证资源访问的公平性,避免因为某些线程执行时间过长导致其他线程等待时间过长。其次,同步机制要尽可能的避免死锁的发生,尤其要注意线程之间的依赖关系。最后,同步机制的实现要尽可能地简单,避免过于复杂的代码实现带来的维护成本。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值