理解线程(线程安全)

  线程安全,指的是当前操作是原子性的。

原子操作线程安全

StringBuffer是线程安全,而StringBuilder是线程不安全的

对于安全与不安全没有深入的理解情况下,易造成这样的错觉:
如果对于StringBuffer的操作均是线程安全的,然而,JAVA给你的保证的线程安全,是说它的方法是执行是排它的

而不是对这个对象本身的多次调用情况下,还是安全的

例子

看看下边的例子:
在StringBufferTest中有一个数据成员contents它是用来扩展的,它的每一次append是线程安全的,但众多次append的组合并不是线程安全的

这个输出结果不是太可控的,但如果对于log和getContest方法加关键字synchronized,那么结果就会变得非常条理

如果换成StringBuider甚至是append到一半,它也会让位于其它在此基础上操作的线程:

public class StringBufferTest {
   private StringBuffer contents = new StringBuffer();
   public void log(String message){
      contents.append(System.currentTimeMillis());
      contents.append("; ");
      contents.append(Thread.currentThread().getName());
      for(int i=0;i<10000;i++){
        contents.append(i);
          contents.append(message);    //append本身是线程安全的,修改contents时,其它线程无法访问。
          contents.append("\n");
      }
      contents.append("\n\n");
   }
   public void getContents(){
      System.out.println(contents);
   }
}

class RunThread extends Thread{
   String message;
   StringBufferTest buffer;
   public RunThread(StringBufferTest buffer, String message){
      this.buffer = buffer;
      this.message = message;
   }
   public void run(){
      while(true){
         buffer.log(message);
         buffer.getContents();
      }
   }
   public static void main(String[] args) {
      StringBufferTest ss = new StringBufferTest();
      new RunThread(ss, "you").start();
      new RunThread(ss, "me").start();
      new RunThread(ss, "she").start();
   }
}

多线程安全

StringBuilder和StringBuffer的方法是一模一样,就是一个多线程和一个单线程的问题

多个线程调用同一StringBuffer 的append方法,这跟他是不是线程安全没有关系的

除非你的结果是append的一系列字符串变乱了,那才能说明他是线程不安全的

线程安全是指任何时刻都只有一个线程访问临界资源

线程安全,并不是说他的一系列操作是同步的

只是对于他执行某个方法的时候不允许别的线程去改变

针对一个类来说是不是线程安全就要看,多个线程在同时在运行,这些线程可能会同时执行某个方法

但是每次运行结果和单线程执行的结果一样,那么就可以说是线程安全的

因为log方法没有上锁,每个现在在append锁释放后,都可能得到cpu的执行片段

避免误解多线安全

但不要对多线程安全存在误解:

public String toString(){
StringBuffer buffer = new StringBuffer();
buffer.append(‘<’);
buffer.append(this.name);
buffer.append(‘>’);
return buffer.toString();
}

这个代码是完全线程安全的

在方法内部定义的变量,在每个线程线程进入的时候都会创建这个局部变量!不涉及线程安全问题

通常涉及系统安全的变量一般都是成员变量!

stringBuffer本身的内部实现是线程安全的!

线程安全那是类本身提供的功能是安全的

你提供插入一个字符串,那么这个字符串插入是安全的

但是要插入两个字符串,两个的顺序你来定,这之间如果有别的插入出错就不管类的事情了,是你自己代码的问题

转自

Java集合中那些类是线程安全的,作者:mexican_ok

时间: 2024-10-22 16:51:42

理解线程(线程安全)的相关文章

深入理解 Java 线程池

目录   一.简介  二.Executor 框架  三.ThreadPoolExecutor  四.Executors  参考资料 一.简介 什么是线程池 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务. 为什么要用线程池 如果并发请求数量很多,但每个线程执行的时间很短,就会出现频繁的创建和销毁线程.如此一来,会大大降低系统的效率,可能频繁创建和销毁线程的时间.资源开销要大于实际工作的所需. 正是由于这个问题,所以有必要引入线程池.使用 线程池的好处 有

由浅入深理解Java线程池及线程池的如何使用

前言 多线程的异步执行方式,虽然能够最大限度发挥多核计算机的计算能力,但是如果不加控制,反而会对系统造成负担.线程本身也要占用内存空间,大量的线程会占用内存资源并且可能会导致Out of Memory.即便没有这样的情况,大量的线程回收也会给GC带来很大的压力. 为了避免重复的创建线程,线程池的出现可以让线程进行复用.通俗点讲,当有工作来,就会向线程池拿一个线程,当工作完成后,并不是直接关闭线程,而是将这个线程归还给线程池供其他任务使用. 接下来从总体到细致的方式,来共同探讨线程池. 总体的架构

C#线程 线程进阶

第四部分:高级线程 非阻塞同步 前面我们说过,即使在分配或增加字段的简单情况下,也需要同步.尽管锁定始终可以满足此需求,但是竞争性锁定意味着线程必须阻塞,从而遭受上下文切换的开销和调度的延迟,这在高度并发且对性能至关重要的情况下是不希望的. .NET Framework的非阻塞同步结构可以执行简单的操作,而无需阻塞,暂停或等待. 正确编写非阻塞或无锁的多线程代码非常棘手!特别是,内存障碍很容易出错(volatile关键字甚至更容易出错).在解除普通锁之前,请仔细考虑是否真的需要性能优势.请记住,

线程系列04,传递数据给线程,线程命名,线程异常处理,线程池

本篇体验:如何传递数据给线程,如何给线程命名,线程的异常处理,线程池.实在是太基础的部分. □ 传递数据给线程 ※ 使用Lambda表达式 class Program { static void Main(string[] args) { Thread t = new Thread(() => Say("hello", "world")); t.Start(); } static void Say(string msg, string msg1) { Cons

线程系列01,前台线程,后台线程,线程同步

在控制台应用程序集中,Main方法开始的是一个线程.如果要再创建线程,需要用到System.Threading这个命名空间. □ 创建第一个线程 using System; using System.Threading; namespace ConsoleApplication4 { class Program { static void Main(string[] args) { var thread = new Thread(DoSth); thread.Start(); } static

死锁现象与解决方案,开启线程的2种方式,守护线程,线程VS进程,线程互斥锁,信号量

死锁现象与解决方案 from threading import Thread,Lock,active_count import time mutexA=Lock() # 锁1 mutexB=Lock() # 锁2 class Mythread(Thread): def run(self): self.f1() self.f2() def f1(self): mutexA.acquire() print('%s 拿到A锁' %self.name) mutexB.acquire() print('%

线程的创建 验证线程之间共享数据 守护线程 线程进程效率对比 锁 死锁 递归锁

线程(from threading import Thread):CPU调度的最小单位 线程的两种创建方式:方式一: 1 from threading import Thread 2 def f1(i): 3 print(i) 4 if __name__ == '__main__': 5 for i in range(10): 6 t = Thread(target=f1,args=(i,)) 7 t.start() 8 print('主线程') 方式二: 1 from threading im

理解RxJava线程模型

RxJava作为目前一款超火的框架,它便捷的线程切换一直被人们津津乐道,本文从源码的角度,来对RxJava的线程模型做一次深入理解.(注:本文的多处代码都并非原本的RxJava的源码,而是用来说明逻辑的伪代码) 入手体验 RxJava 中切换线程非常简单,例如最常见的异步线程处理,主线程回调的模型,可以很优雅的用如下代码来做处理: Observable.just("magic") .map(str -> doExpensiveWork(str)) .subscribeOn(Sch

爸爸和儿子的故事带你理解java线程

今天回想线程方面的知识,发现一个非常有意思的小程序.是用来说明多线程的以下贴出来分享下,对刚開始学习的人理解线程有非常大的帮助 爸爸和儿子的故事 <span style="font-family:KaiTi_GB2312;font-size:18px;">public class FatherThread extends Thread{ @Override public void run() { System.out.println("爸爸想抽烟.发现烟抽完了&q

Java多线程理解(线程安全)

我们在使用Java多线程时,一定需要考虑到共享,线程安全的相关内容.以下通过几个例子帮助大家来理解多线程时如何运行的,后续通过一篇文章详述解决办法:synchronized. 场景1: 第一次运行结果: [当前线程]----------one=====实例变量的值----x=1 [当前线程]----------two=====实例变量的值----x=2 [当前线程]----------two=====实例变量的值----x=3 [当前线程]----------two=====实例变量的值----