`
a418040445
  • 浏览: 26342 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

java 基础,关于线程安全 (转)

    博客分类:
  • java
 
阅读更多
 线程安全的本质体现在两个方面,

  A变量安全:多线程同时运行一段代码

  B线程同步:一个线程还没执行完,另一个线程又进来接着执行。

 看个简单的例子。

Java代码
public class ThreadSafe implements java.lang.Runnable {   
       
    int num = 1;   
    public void run() {   
        for (int i = 0; i < 3; i++) {   
            num = num + 1;   
            try {   
                Thread.sleep(2000);   
            } catch (InterruptedException e) {   
                e.printStackTrace();   
            }   
            System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + num);   
        }   
    }   
   
}   
public class ThreadSafe implements java.lang.Runnable {
int num = 1;
public void run() {
for (int i = 0; i < 3; i++) {
num = num + 1;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + num);
}
}
}
  
TestMan.java 写道
package com.java.thread.test;

public class TestMan {
public static void main(String[] args) {
Runnable safe=new ThreadSafe();
Thread thread1=new Thread(safe,"thread1");
Thread thread2=new Thread(safe,"thread2");
thread1.start();
thread2.start();
}

}
 运行结果

num is value +===thread2---------3
num is value +===thread1---------4
num is value +===thread2---------5
num is value +===thread1---------6
num is value +===thread1---------7
num is value +===thread2---------7


很明显是错误的,应为两个线程共享同一个变量。这里就是变量的安全问题。

解决办法:

1抛弃单实例,多线程的方式,用多实例,多线程的方式,这样就和单线程是一个样了,不会出错,但是是最接近传统的编程模式

2不要用类的实例变量,经可能把变量封装到方法内部。

1类的解决办法的代码。

Java代码
public class TestMan {   
    public static void main(String[] args) {   
        Runnable safe=new ThreadSafe();   
        Runnable safe2=new ThreadSafe();   
        Thread thread1=new Thread(safe,"thread1");   
        Thread thread2=new Thread(safe2,"thread2");   
        thread1.start();   
        thread2.start();   
    }   
   
}   
public class TestMan {
public static void main(String[] args) {
Runnable safe=new ThreadSafe();
Runnable safe2=new ThreadSafe();
Thread thread1=new Thread(safe,"thread1");
Thread thread2=new Thread(safe2,"thread2");
thread1.start();
thread2.start();
}
}

  
运行结果

num is value +===thread1---------2
num is value +===thread2---------2
num is value +===thread1---------3
num is value +===thread2---------3
num is value +===thread1---------4
num is value +===thread2---------4
2类解决办法的代码

Java代码 
public class ThreadSafe implements java.lang.Runnable {   
       
    public void run() {   
        int num = 1;   
        for (int i = 0; i < 3; i++) {   
            num = num + 1;   
            try {   
                Thread.sleep(2000);   
            } catch (InterruptedException e) {   
                e.printStackTrace();   
            }   
            System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + num);   
        }   
    }   
   
}   
public class ThreadSafe implements java.lang.Runnable {
public void run() {
int num = 1;
for (int i = 0; i < 3; i++) {
num = num + 1;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + num);
}
}
}
  
Java代码 
public class TestMan {   
    public static void main(String[] args) {   
        Runnable safe=new ThreadSafe();   
   
        Thread thread1=new Thread(safe,"thread1");   
        Thread thread2=new Thread(safe,"thread2");   
        thread1.start();   
        thread2.start();   
    }   
   
}   
public class TestMan {
public static void main(String[] args) {
Runnable safe=new ThreadSafe();
Thread thread1=new Thread(safe,"thread1");
Thread thread2=new Thread(safe,"thread2");
thread1.start();
thread2.start();
}
}

 运行结果

num is value +===thread2---------2
num is value +===thread1---------2
num is value +===thread1---------3
num is value +===thread2---------3
num is value +===thread1---------4
num is value +===thread2---------4

 



这两种办法,比较推荐适用第二个办法,就是把变量经可能的封装到风发内部,这样他们就是线程的私有变量了。另外,从jdk1.2后,推出了 threadlocal 对象,它作为线程的一个局部变量,可以为每个线程创建一个副本,用来保存每个线程的属性,各是各的,互不干扰。单每个 threadlocal变量只能保存一个变量,假如有多个变量要保存,那么就要写多个threadlocal对象。



我们把代码改写一下。

Java代码
public class ThreadSafe implements java.lang.Runnable {   
    ThreadLocal<Integer> local=new ThreadLocal<Integer>();   
    public void run() {   
        for (int i = 0; i < 3; i++) {   
            if(local.get()==null){   
                local.set(new Integer(1));   
            }   
            int num=local.get().intValue();   
            num=num+1;   
            local.set(new Integer(num));   
            try {   
                Thread.sleep(2000);   
            } catch (InterruptedException e) {   
                e.printStackTrace();   
            }   
            System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + local.get().intValue());   
        }   
    }   
   
}   
public class ThreadSafe implements java.lang.Runnable {
ThreadLocal<Integer> local=new ThreadLocal<Integer>();
public void run() {
for (int i = 0; i < 3; i++) {
if(local.get()==null){
local.set(new Integer(1));
}
int num=local.get().intValue();
num=num+1;
local.set(new Integer(num));
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + local.get().intValue());
}
}
}
  
Java代码 
public class TestMan {   
    public static void main(String[] args) {   
        Runnable safe=new ThreadSafe();   
        Thread thread1=new Thread(safe,"thread1");   
        Thread thread2=new Thread(safe,"thread2");   
        thread1.start();   
        thread2.start();   
    }   
   
}   
public class TestMan {
public static void main(String[] args) {
Runnable safe=new ThreadSafe();
Thread thread1=new Thread(safe,"thread1");
Thread thread2=new Thread(safe,"thread2");
thread1.start();
thread2.start();
}
}

 运行结果

num is value +===thread2---------2
num is value +===thread1---------2
num is value +===thread1---------3
num is value +===thread2---------3
num is value +===thread1---------4
num is value +===thread2---------4



结果是一样的,所以这里变量安全有3个办法可以解决。



然后在说说线程的同步的问题。我们看上面的运行结果。

num is value +===thread2---------2
num is value +===thread1---------2
num is value +===thread1---------3
num is value +===thread2---------3
num is value +===thread1---------4
num is value +===thread2---------4

就 可以看出他们不是线程同步的,是thread1和thread2在交替执行的。在有些情况下,要求一段代码在运行的过程中是一个不可分割的实体,就是原子的。就是说当已经有线程在执行这段代码的时候,其他的线程必须等待他执行完毕后才能竟来执行,这就是所谓的线程同步。



java通过同步锁来执行线程的同步和等待,也就是说,要不间断执行的代码需要放在synchronized关键字标识的代码块中。可以用来修饰代码块,也可以修饰方法。



Java代码

public class ThreadSafe implements java.lang.Runnable{   
    public synchronized void run() {   
        int num = 1;   
        for (int i = 0; i < 3; i++) {   
            num = num + 1;   
            try {   
                Thread.sleep(2000);   
            } catch (InterruptedException e) {   
                e.printStackTrace();   
            }   
            System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + num);   
        }   
    }   
   
   
}   
public class ThreadSafe implements java.lang.Runnable{
public synchronized void run() {
int num = 1;
for (int i = 0; i < 3; i++) {
num = num + 1;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + num);
}
}
}

  
Java代码 
public class TestMan {   
    public static void main(String[] args) {   
        Runnable safe=new ThreadSafe();   
        Thread thread1=new Thread(safe,"thread1");   
        Thread thread2=new Thread(safe,"thread2");   
        thread1.start();   
        thread2.start();   
    }   
   
}   
public class TestMan {
public static void main(String[] args) {
Runnable safe=new ThreadSafe();
Thread thread1=new Thread(safe,"thread1");
Thread thread2=new Thread(safe,"thread2");
thread1.start();
thread2.start();
}
}

 运行结果

um is value +===thread1---------2
num is value +===thread1---------3
num is value +===thread1---------4
num is value +===thread2---------2
num is value +===thread2---------3
num is value +===thread2---------4

 



可以看到thread1运行结束后thread2才开始运行的。代码还可以这么写

Java代码

public class ThreadSafe implements java.lang.Runnable {   
    public void run() {   
        int num = 1;   
        synchronized (this) {   
            for (int i = 0; i < 3; i++) {   
                num = num + 1;   
                try {   
                    Thread.sleep(2000);   
                } catch (InterruptedException e) {   
                    e.printStackTrace();   
                }   
                System.out.println("num is value +==="   
                        + Thread.currentThread().getName() + "---------" + num);   
            }   
        }   
    }   
   
}   
public class ThreadSafe implements java.lang.Runnable {
public void run() {
int num = 1;
synchronized (this) {
for (int i = 0; i < 3; i++) {
num = num + 1;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("num is value +==="
+ Thread.currentThread().getName() + "---------" + num);
}
}
}
}
  


在启用同步锁机制以后,需要避免

1无线等待,,线程B等待线程A执行完毕,然后线程A确进入了死循环。

2循环等待:两个线程相互调用,都要求要同步执行,这个时候就先会循环等待,我等你执行,你也在等我执行,这个时候就死锁了

转自:http://www.blogjava.net/lingyu/articles/322848.html
分享到:
评论

相关推荐

    Java多线程安全集合

    理解并熟练运用这些线程安全集合是构建健壮、高性能的多线程Java应用程序的基础。它们能帮助开发者编写出更安全、更高效的代码,避免因并发问题导致的错误。同时,根据具体场景选择合适的集合类型,可以极大地提高...

    java基础多线程练习题(1)

    总结来说,Java基础多线程练习题主要涵盖了线程的创建、同步与通信、线程安全以及并发工具的使用。通过这些题目,你可以更好地理解线程的工作原理,学会在实际项目中有效利用多线程提高程序性能,避免潜在的问题。在...

    java集合类线程安全.doc

    本文将结合上述 Bloch 关于线程安全等级的定义,对 Java 集合框架中的集合类进行线程安全性分析,并指出各个集合类在现实的编程环境中需要注意的并发编程的陷阱;同时对集合框架中通用算法对线程安全性的影响进行...

    java线程线程安全同步线程

    总的来说,理解和掌握Java线程的创建、状态管理、同步机制和线程安全是进行多线程编程的基础,这对于开发高效、稳定的并发程序至关重要。在实际编程中,应充分利用Java提供的工具和机制,避免潜在的并发问题,提升...

    Java线程安全问题_动力节点Java学院整理

    其实java的多线程并发问题最终都会反映在java的内存模型上,所谓线程安全无非是要控制多个线程对某个资源的有序访问或修改。总结java的内存模型,要解决两个主要的问题:可见性和有序性。我们都知道计算机有高速缓存...

    Java多线程机制(讲述java里面与多线程有关的函数)

    Java程序中的线程是在操作系统级别的线程基础上进行抽象的。每个Java程序都有一个主线程,即由JVM启动并执行main方法的线程。线程代表了程序中的执行流,可以在不同的线程之间切换以共享CPU时间。线程的状态包括新建...

    JAVAJAVA多线程教学演示系统论文

    4. **线程安全与死锁**:论文会讨论线程安全问题,如数据竞争和活锁,并分析如何预防和解决这些问题。同时,会介绍死锁的概念、死锁的四个必要条件,以及如何避免死锁的策略。 5. **多线程教学演示系统设计**:这...

    java多线程安全性基础介绍.pptx

    java多线程安全性基础介绍 线程安全 正确性 什么是线程安全性 原子性 竞态条件 i++ 读i ++ 值写回i 可见性 JMM 由于cpu和内存加载速度的差距,在两者之间增加了多级缓存导致,内存并不能直接对cpu可见。 ...

    关于线程(java)两天的课件

    最后,线程安全的数据结构如ConcurrentHashMap、Atomic变量等,能够保证在多线程环境下正确地操作数据,提升并发性能。理解并熟练掌握这些概念和工具,是成为一名优秀的Java并发程序员必不可少的步骤。 总之,本...

    Java多线程知识点总结

    Java提供了多种机制来保证线程安全,比如使用synchronized关键字来同步方法或代码块,实现线程之间的同步。当一个线程试图进入一个已经被另一个线程持有的同步代码块时,它将进入阻塞状态,直到同步代码块的执行线程...

    java多线程经典案例

    此外,Java 5引入了BlockingQueue阻塞队列,它是一种线程安全的数据结构,线程可以等待队列中有数据可取或等待队列有空位可存,常用于生产者-消费者模型。 线程阻塞是指线程在运行过程中因为某些原因无法继续执行,...

    java 多线程操作数据库

    1. **多线程基础**:多线程是Java编程中的一个重要概念,允许程序同时执行多个任务。在本示例中,通过创建多个`Thread`对象并调用它们的`run()`方法来实现并行处理数据库操作。 2. **数据库连接管理**:在多线程...

    java实现多线程文件传输

    1. **线程基础**:在Java中,线程是程序执行的基本单元,可以通过实现`Runnable`接口或继承`Thread`类来创建。`Runnable`接口更利于实现多线程,因为它允许实现类与其他接口一起使用,而`Thread`类则直接提供了线程...

    java多线程处理数据库数据

    1. **线程安全**:由于多线程环境下可能存在数据竞争,所以在访问共享资源(如数据库连接)时,需要确保线程安全。可以使用`synchronized`关键字或者`Lock`来同步访问。 2. **事务管理**:在多线程环境中,可能需要...

    java基础,多线程,反射

    Java提供了`synchronized`关键字、`wait()`, `notify()` 和 `notifyAll()` 方法,以及`java.util.concurrent`包下的高级并发工具如`Semaphore`, `CyclicBarrier`, 和 `CountDownLatch`等,来确保线程安全和避免竞态...

    java Socket 多线程

    在多线程环境下,共享资源(如Socket的输入/输出流)可能引发线程安全问题。因此,如果多个线程需要访问同一资源,需要使用`synchronized`关键字或者`java.util.concurrent`包下的工具来保证数据一致性,防止数据...

    java多线程设计模式_java_设计模式_多线程_多线程课题_

    Java提供了一些线程安全的集合类,如ConcurrentHashMap、CopyOnWriteArrayList和CopyOnWriteArraySet,它们在多线程环境下提供了高并发的访问性能。 九、死锁检测与避免 死锁是多线程编程中的常见问题,两个或多个...

    JAVA多线程教材

    8. **线程安全与线程不安全**:理解哪些操作是线程安全的,哪些不是,以及如何使非线程安全的操作变得安全,是多线程编程的重要课题。线程安全的类如Atomic系列类和Collections.synchronizedXXX()方法可以帮助我们...

Global site tag (gtag.js) - Google Analytics