我正在学习编写线程安全的程序以及如何评估非线程安全的代码.
如果一个类在由多个线程执行时正常运行,则该类被认为是线程安全的.
我的Counter.java不是一个线程安全的,但输出是按照预期从0到9打印的所有3个线程.
谁能解释为什么?以及线程安全如何工作?
public class Counter {
private int count = 0;
public void increment() {
count++;
}
public void decrement() {
count--;
}
public void print() {
System.out.println(count);
}
}
public class CountThread extends Thread {
private Counter counter = new Counter();
public CountThread(String name) {
super(name);
}
public void run() {
for (int i=0; i<10; i++) {
System.out.print("Thread " + getName() + " ");
counter.print();
counter.increment();
}
}
}
public class CounterMain {
public static void main(String[] …Run Code Online (Sandbox Code Playgroud) 我一直在考虑向Java语言架构师发送一个提案.
在同步块中
synchronized(lock) {
// If there is no notification before this point
// <--- implicitly put here // lock.notifyAll(); // OR // lock.notify();
}
Run Code Online (Sandbox Code Playgroud)
线程离开同步块后,它不能再调用lock.notifyAll()/ lock.notify()而不会出现异常.
忘记通知其他线程监视器持有者可能会永远让他们(其他线程)等待(除非他们在等待方法中放置了一些超时).
synchronized(lock) {
lock.wait(); //<--- this thread may forever freeze here
}
Run Code Online (Sandbox Code Playgroud)
我无法想象这样的行为(在没有明确通知的情况下在同步块的末尾插入隐式通知)是不合需要的.
相同的方法可以应用于同步方法.
如何(技术上)实现此类行为可以有不同的方式,例如:
@autonotify
synchronized(lock) {
...
}
@autonotify
public void synchronized doSomething() {
...
}
Run Code Online (Sandbox Code Playgroud)
要么:
@autonotifyAll
synchronized(lock) {
...
}
@autonotifyAll
public void synchronized doSomething() {
...
}
Run Code Online (Sandbox Code Playgroud)
或者 - 使自动通知成为默认行为,但保留抑制它的能力,例如:
@suppressautonotify
synchronized(lock) {
...
}
@suppressautonotifyAll
public void …Run Code Online (Sandbox Code Playgroud) 当我遇到使用wait/notify方法的例子时,我正在查看Kathy Sierra书中的Threading章节:
class ThreadA {
public static void main(String [] args) {
ThreadB b = new ThreadB();
b.start();
synchronized(b) {
try {
System.out.println("Waiting for b to complete...");
b.wait();
} catch (InterruptedException e) {}
System.out.println("Total is: " + b.total);
}
}
}
class ThreadB extends Thread {
int total;
public void run() {
synchronized(this) {
for(int i=0;i<100;i++) {
total += i;
}
notify();
}
}
}
Run Code Online (Sandbox Code Playgroud)
运行代码总是产生相同的输出:
等待b完成......总计是:4950
我在ThreadB中修改了run()的synchronized块,添加:
System.out.println("ThreadB is executed");
Run Code Online (Sandbox Code Playgroud)
问题是:我为什么一直这样做
"等待b完成......"
之前
"执行ThreadB"
?是不是有可能在主线程之前执行线程b?
我有以下测试项目:
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class myThreadTest {
private static final Logger log = LoggerFactory.getLogger(myThreadTest.class);
private ScheduledExecutorService executorService1 = Executors.newSingleThreadScheduledExecutor();
private ScheduledExecutorService executorService2 = Executors.newSingleThreadScheduledExecutor();
private Future<?> task1;
private Future<?> task2;
private class Task1 implements Runnable {
@Override
public synchronized void run() {
log.debug("-----------------------");
for (int i = 0; i < 100; i++) {
log.debug("{} Hello from Task 1",i);
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug("-----------------------"); …Run Code Online (Sandbox Code Playgroud) 我听说有人说var ++和++ var这样的语句不是线程安全的,所以我写了一个应用程序进行测试.代码如下:
unsigned long gCounter = 0;
const unsigned long WORKS = 1048576; // pow(2, 20)
const unsigned long MAX_THREADS = 100;
const unsigned long WORKER_THREADS = 2;
unsigned long GetCounter(){
return gCounter++;
}
void *WorkerThread(void *){
unsigned long items = 0;
do {
GetCounter();
items++;
} while(items < WORKS);
printf("Exiting thread: %lu\n", pthread_self());
return NULL;
}
int main(int argc, char* argv[]){
pthread_t workers[MAX_THREADS];
//create two threads
for (int i = 0; i < WORKER_THREADS; i++){
pthread_create(&workers[i], NULL, WorkerThread, …Run Code Online (Sandbox Code Playgroud) 我不明白为什么这个简单的python示例执行的时间比它应该多5倍:/我查看代码2小时,在Google等上搜索...我真的没有看到这里的问题.任何帮助,将不胜感激!
import urllib2
import socket
import Queue
import threading
socket.setdefaulttimeout(10)
verbose = True
hosts = ['game1', 'game2', 'game3', 'game4', 'game5', 'game6']
queue = Queue.Queue()
class ThreadUrl(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
def run(self):
while True:
host = self.queue.get()
url = 'http://{0}.server.com'.format(host)
f = urllib2.urlopen(url)
print f.read(1024)
self.queue.task_done()
def main():
for i in range(5):
t = ThreadUrl(queue)
t.setDaemon(True)
t.start()
for host in hosts:
queue.put(host)
queue.join()
if __name__ == '__main__':
main()
Run Code Online (Sandbox Code Playgroud) 这个班是一个单身人士.我不太擅长线程安全.这个类是线程安全的吗?省略了一些方法,但它们仅用于一个线程.这里列出的方法将同时从多个线程访问.
public class TermsDto {
private final static MapSplitter mapSplitter = Splitter
.on(',').trimResults().omitEmptyStrings()
.withKeyValueSeparator(":");
private volatile double factorForOthers = 4;
private volatile Map<String, Double> factorForTermName =
new HashMap<String, Double>();
public void setFactorForOthers(double factorForOthers) {
this.factorForOthers = factorForOthers;
}
public void setFactorForTermNameMapping(String mapping) {
HashMap<String, Double> tempFactorForTermName =
new HashMap<String, Double>();
for (Map.Entry<String, String> entry :
mapSplitter.split(mapping).entrySet()) {
double factor = Double.parseDouble(entry.getValue());
tempFactorForTermName.put(entry.getKey(), factor);
}
factorForTermName = tempFactorForTermName;
}
}
Run Code Online (Sandbox Code Playgroud) 我编写了一个Java ReadWriteLock,读者使用双重检查锁定来获取写锁定.这是不安全的(对于具有延迟实例化的DCL的情况)?
import java.util.concurrent.atomic.AtomicInteger;
public class DCLRWLock {
private boolean readerAcquiringWriteLock = false;
private boolean writerLock = false;
private AtomicInteger numReaders = new AtomicInteger();
public void readerAcquire() throws InterruptedException {
while (!nzAndIncrement(numReaders)) {
synchronized (this) {
if (numReaders.get() != 0)
continue;
if (readerAcquiringWriteLock) {
do {
wait();
} while (readerAcquiringWriteLock);
} else {
readerAcquiringWriteLock = true;
writerAcquire();
readerAcquiringWriteLock = false;
assert numReaders.get() == 0;
numReaders.set(1);
notifyAll();
break;
}
}
}
}
public void readerRelease() {
if (numReaders.decrementAndGet() == 0)
writerRelease(); …Run Code Online (Sandbox Code Playgroud) java atomic thread-safety readwritelock double-checked-locking
AFAIK是多线程编程的主要目标,它通过利用多个处理内核来提高性能.关键是最大化并行执行.
当我看到线程安全的通用数据结构类时,我觉得有些讽刺.因为线程安全意味着强制执行串行执行(锁定,原子操作或其他),所以它是反并行的.线程安全类意味着序列化被封装并隐藏在类中,因此我们将有更多机会强制执行串行 - 失去性能.在较大(或最大)单元 - 应用程序逻辑中管理这些关键部分会更好.
那么为什么人们想要线程安全的类呢?他们的真正好处是什么?
PS 我的意思是线程安全类是一个只有线程安全的方法,可以安全地从多个线程同时调用.安全意味着它保证正确的读/写结果.正确表示其结果等于单线程执行时的结果.(例如避免ABA问题)
所以我认为我的问题中的术语线程安全包含了定义的串行执行.这就是为什么我对它的目的感到困惑并问了这个问题.
我的项目中有很多代码,如Hit和静音,通过这种方式使用Reactive扩展:
IDisposable dsp = null;
dsp = TargetObservable.Subscribe((incomingContent) =>
{
if (incomingContent == "something")
{
myList.Add(incomingContent);
dsp.Dispose();
}
});
Run Code Online (Sandbox Code Playgroud)
首先,我担心线程的安全性,因为我的Observable非常繁忙并且一直有大量内容推送,但后来,我被告知我应该结合ObserveOn(thread)保证线程安全,我完全同意,所以让我们忘记了线程安全的事情.
在这里,我想知道:
Take(count)'TakeWhile(预测)'?OnComplete()被调用,Dispose()将在内部调用,对吗?然后Observer和Observable之间的引用关系将中断(因为我的observable是一个长寿命的静态实例,引用会导致内存泄漏).