`
haoningabc
  • 浏览: 1476960 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java线程,并发基础

    博客分类:
  • java
阅读更多
学习hadoop,nio和线程用的很多,基础从这里找吧
从csdn下的
http://dl.iteye.com/upload/picture/pic/84809/2e8a1e5f-2c36-3cfa-8c3c-acb471e607f3.jpg
关于util.concurrent,查看
http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html
关于concurrentMap,参考
http://blog.csdn.net/waitforcher/archive/2009/05/24/4211896.aspx
把jpg扩展名改成zip,解压后是ibm的线程的教程
单个变量的准确性用volatile,多变量(类似事务)用synchronized
Collections 类提供了一组便利的用于 List、Map 和 Set 接口的封装器,可以用 Collections.synchronizedMap 封装 Map,它将确保所有对该映射的访问都被正确同步。
jdk1.6有个concurrentMap
-------------------------------
概念:
---------------------------------
同步可以让我们确保线程看到一致的内存视图。

处理器可以使用高速缓存加速对内存的访问(或者编译器可以将值存储到寄存器中以便进行更快的访问)。在一些多处理器体系结构上,如果在一个处理器的高速缓存中修改了内存位置,没有必要让其它处理器看到这一修改,直到刷新了写入器的高速缓存并且使读取器的高速缓存无效。

这表示在这样的系统上,对于同一变量,在两个不同处理器上执行的两个线程可能会看到两个不同的值!这听起来很吓人,但它却很常见。它只是表示在访问其它线程使用或修改的数据时,必须遵循某些规则。

Volatile 比同步更简单,只适合于控制对基本变量(整数、布尔变量等)的单个实例的访问。当一个变量被声明成 volatile,任何对该变量的写操作都会绕过高速缓存,直接写入主内存,而任何对该变量的读取也都绕过高速缓存,直接取自主内存。这表示所有线程在任何时候看到的 volatile 变量值都相同。

如果没有正确的同步,线程可能会看到旧的变量值,或者引起其它形式的数据损坏
---------------------------------------------------
例子:
----------------------------------------------------
//在一定时间内计算素数:注意volatile 的使用
public class CalculatePrimes extends Thread {
    public static final int MAX_PRIMES = 1000000;
    public static final int TEN_SECONDS = 1000;
    public volatile boolean finished = false;
    public void run() {
        int[] primes = new int[MAX_PRIMES];
        int count = 0;
        for (int i=2; count<MAX_PRIMES; i++) {
            // Check to see if the timer has expired
            if (finished) {
                break;
            }
            boolean prime = true;
            for (int j=0; j<count; j++) {
                if (i % primes[j] == 0) {
                    prime = false;
                    break;
                }
            }
            if (prime) {
                primes[count++] = i;
                System.out.println("Found prime: " + i);
            }
        }
    }
    public static void main(String[] args) {
        CalculatePrimes calculator = new CalculatePrimes();
        calculator.start();
        try {
            Thread.sleep(TEN_SECONDS);
        }
        catch (InterruptedException e) {
            // fall through
        }
        calculator.finished = true;
    }
}


//定时结束标识
import java.util.Timer;
import java.util.TimerTask;
public class CalculatePrimesTest {
	public static void main(String[] args) {
		Timer timer = new Timer();

		final CalculatePrimes calculator = new CalculatePrimes();
		calculator.start();

		timer.schedule(new TimerTask() {
			public void run() {
				calculator.finished = true;
			}
		}, CalculatePrimes.TEN_SECONDS);
	}
}


//多线程得到大数组的最大值
public class TenThreads {
    private static class WorkerThread extends Thread {
        int max = Integer.MIN_VALUE;
        int[] ourArray;
        public WorkerThread(int[] ourArray) {
            this.ourArray = ourArray;
        }
        // Find the maximum value in our particular piece of the array
        public void run() {
            for (int i = 0; i < ourArray.length; i++) 
                max = Math.max(max, ourArray[i]);                
        }
        public int getMax() {
            return max;
        }
    }
    public static void main(String[] args) {
        WorkerThread[] threads = new WorkerThread[10];
        int[][] bigMatrix = {{12,3,42,3,4},{12,3,42,3,4},{12,3,42,3,4},{12,3,42,3,4},{12,3,42,3,4},{12,3,42,3,4},{12,3,42,3,4},{12,3,42,3,4},{12,3,42,3,4},{12,3,42,3,4}};//getBigHairyMatrix();
        int max = Integer.MIN_VALUE;
        // Give each thread a slice of the matrix to work with
        for (int i=0; i < 10; i++) {
            threads[i] = new WorkerThread(bigMatrix[i]);
            threads[i].start();
        }
        // Wait for each thread to finish
        try {
            for (int i=0; i < 10; i++) {
                threads[i].join();
                max = Math.max(max, threads[i].getMax());
            }
        }
        catch (InterruptedException e) {
            // fall through
        }
        System.out.println("Maximum value was " + max);
    }
}

使用synchronized 的例子:
使用 synchronized 块可以让您将一组相关更新作为一个集合来执行,而不必担心其它线程中断或看到计算的中间结果。以下示例代码将打印“1 0”或“0 1”。如果没有同步,它还会打印“1 1”

haoning:这里锁了一个对象,所以在两个对象里同时调用第三个对象的锁,保证是一个锁,下面另一个例子不是一个锁所以互不影响
public class SyncExample {
	private static Object lockObject = new Object();
	private static int x, y;
	private static class Thread1 extends Thread {
		public void run() {
			synchronized (lockObject) {
				x = y = 0;
				System.out.println(x);
			}
		}
	}
	private static class Thread2 extends Thread {
		public void run() {
			synchronized (lockObject) {
				x = y = 1;
				System.out.println(y);
			}
		}
	}
	public static void main(String[] args) {
		new Thread1().run();
		new Thread2().run();
	}
}


Java 锁定合并了一种互斥形式。每次只有一个线程可以持有锁。锁用于保护代码块或整个方法,必须记住是锁的身份保护了代码块,而不是代码块本身,这一点很重要。一个锁可以保护许多代码块或方法。

反之,仅仅因为代码块由锁保护并不表示两个线程不能同时执行该代码块。它只表示如果两个线程正在等待相同的锁,则它们不能同时执行该代码。

在以下示例中,两个线程可以同时不受限制地执行 setLastAccess() 中的 synchronized 块,因为每个线程有一个不同的 thingie 值。因此,synchronized 代码块受到两个正在执行的线程中不同锁的保护。
import java.util.Date;
public class SyncExampleTest {
	public static class Thingie {
		private Date lastAccess;
		public synchronized void setLastAccess(Date date) {
			this.lastAccess = date;
			System.out.println(this.lastAccess);
		}
	}
	public static class MyThread extends Thread {
		private Thingie thingie;

		public MyThread(Thingie thingie) {
			this.thingie = thingie;
		}

		public void run() {
			thingie.setLastAccess(new Date());
		}
	}
	public static void main(String args[]) {
		Thingie thingie1 = new Thingie(), thingie2 = new Thingie();
		new MyThread(thingie1).start();
		new MyThread(thingie2).start();
	}
}

SimpleCache.java 使用 HashMap 为对象装入器提供了一个简单的高速缓存。load() 方法知道怎样按对象的键装入对象。在一次装入对象之后,该对象就被存储到高速缓存中,这样以后的访问就会从高速缓存中检索它,而不是每次都全部地装入它。对共享高速缓存的每个访问都受到 synchronized 块保护。由于它被正确同步,所以多个线程可以同时调用 getObject 和 clearCache 方法,而没有数据损坏的风险
import java.util.HashMap;
import java.util.Map;
public class SimpleCache {
	private final Map cache = new HashMap();
	public Object load(String objectName) {
		// load the object somehow
		return objectName;
	}
	public void clearCache() {
		synchronized (cache) {
			cache.clear();
		}
	}
	public Object getObject(String objectName) {
		Object o;
		synchronized (cache) {
			o = cache.get(objectName);
			if (o == null) {
				o = load(objectName);
				cache.put(objectName, o);
			}
		}
		return o;
	}
}

用于一致性的同步:
/*如果多个线程试图同时使用这个类,会发生什么?这可能是个灾难。因为没有同步,多个线程可以同时执行 push() 和 pop()。如果一个线程调用 push(),而另一个线程正好在递增了 top 并要把它用作 values 的下标之间调用 push(),会发生什么?结果,这两个线程会把它们的新值存储到相同的位置!当多个线程依赖于数据值之间的已知关系,但没有确保只有一个线程可以在给定时间操作那些值时,可能会发生许多形式的数据损坏,而这只是其中之一。
对于这种情况,补救办法很简单:同步 push() 和 pop() 这两者,您将防止线程执行相互干扰。
请注意,使用 volatile 还不够 — 需要使用 synchronized 来确保 top 和 values 之间的关系保持一致。
 */
public class UnsafeStack {
	public int top = 0;
	public int[] values = new int[1000];
	public void push(int n) {
		values[top++] = n;
	}
	public int pop() {
		return values[--top];
	}
}


/* 当我们要递增计数器时,会发生什么?请看 increment() 的代码。它很清楚,但不是线程安全的。如果两个线程试图同时执行 increment(),会发生什么?计数器也许会增加 1,也许增加 2。令人惊奇的是,把 counter 标记成 volatile 没有帮助,使 get() 和 set() 都变成 synchronized 也没有帮助。
设想计数器是零,而两个线程同时执行递增操作代码。这两个线程会调用 Counter.get(),并且看到计数器是零。现在两个线程都对它加一,然后调用 Counter.set()。如果我们的计时不太凑巧,那么这两个线程都看不到对方的更新,即使 counter 是 volatile,或者 get() 和 set() 是 synchronized。现在,即使计数器递增了两次,得到的值也许只是一,而不是二。
要使递增操作正确运行,不仅 get() 和 set() 必须是 synchronized,而且 increment() 也必需是 synchronized!否则,调用 increment() 的线程可能会中断另一个调用 increment() 的线程。如果您不走运,最终结果将会是计数器只增加了一次,不是两次。同步 increment() 防止了这种情况的发生,因为整个递增操作是原子的。
当循环遍历 Vector 的元素时,同样如此。即使同步了 Vector 的方法,但在循环遍历时,Vector 的内容仍然会更改。如果要确保 Vector 的内容在循环遍历时不更改,必须同步整个代码块
*/
public class Counter {
	private int counter = 0;
	public int get() {
		return counter;
	}
	public void set(int n) {
		counter = n;
	}
	public void increment() {
		set(get() + 1);
	}
}

---------------------------
死锁
/*
如果有一组进程或线程,其中每个都在等待一个只有其它进程或线程才可以执行的操作,那么就称它们被死锁了。
最常见的死锁形式是当线程 1 持有对象 A 上的锁,而且正在等待与 B 上的锁,而线程 2 持有对象 B 上的锁,却正在等待对象 A 上的锁。这两个线程永远都不会获得第二个锁,或者释放第一个锁。它们只会永远等待下去。
要避免死锁,应该确保在获取多个锁时,在所有的线程中都以相同的顺序获取锁。
  同步准则:当编写 synchronized 块时,有几个简单的准则可以遵循,这些准则在避免死锁和性能危险的风险方面大有帮助:
使代码块保持简短。Synchronized 块应该简短 — 在保证相关数据操作的完整性的同时,尽量简短。把不随线程变化的预处理和后处理移出 synchronized 块。
不要阻塞。不要在 synchronized 块或方法中调用可能引起阻塞的方法,如 InputStream.read()。
在持有锁的时候,不要对其它对象调用方法。这听起来可能有些极端,但它消除了最常见的死锁源头。
*/

分享到:
评论

相关推荐

    Java 模拟线程并发

    Java 模拟线程并发是编程领域中的一个重要概念,尤其在多核处理器和高并发应用中,理解并熟练掌握线程并发技术对于提升程序性能至关重要。在Java中,线程并发可以通过多种方式实现,包括继承Thread类、实现Runnable...

    java 多线程并发实例

    在Java编程中,多线程并发是提升程序执行效率、充分利用多核处理器资源的重要手段。本文将基于"java 多线程并发实例"这个主题,深入探讨Java中的多线程并发概念及其应用。 首先,我们要了解Java中的线程。线程是...

    java线程并发库ppt

    java线程并发库原子操作类与线程池的讲解,自我总结大家分享

    java线程与并发编程实践

    Java线程与并发编程实践是Java开发者必备的技能之一,特别是在多核处理器和高并发应用环境中,有效地管理和利用线程能极大地提升程序的性能。本书《java线程与并发实践编程》由Jeff Friesen撰写,2017年2月出版,...

    JAVA多线程并发编程

    线程并发的使用可以显著提升程序处理能力,例如在服务器端处理大量用户请求时,如果每个请求都由单独的线程处理,那么处理速度将大大提高。但同时,多线程并发也会引入一些问题,如数据竞争和同步问题。 为了解决...

    java多线程并发

    java多线程并发的在新窗口

    java多线程并发演示

    实现多线程的并发执行,能演示操作系统的时间转轮调度算法对多线程程序执行的影响效果,能控制一个或多个线程的执行情况。

    14个Java线程并发面试题和答案..pdf

    "Java线程并发面试题解析" Java线程并发是一种复杂的技术,需要深入理解线程之间的交互、同步机制、死锁、饥饿、活锁等概念。以下是14个Java线程并发面试题和答案的详细解析: 1. 问题:java中的线程是什么? ...

    JAVA零基础到高级进阶特训营 JAVA多线程并发设计+Spring高级+数据库开发+JAVA基础等

    这套课程既可以作为从零基础开始...课程的主要内容涉及有JAVA基础课程、JAVA多线程与并发编程、数据库开发基础和进阶、Spring Framework、Spring进阶、Spring MVC框架、Spring boot、Java常用类库、Java异常处理等等

    Java_多线程与并发编程总结.doc

    Java多线程与并发编程是Java开发中至关重要的一部分,它涉及到如何高效地利用CPU资源,以实现程序的并行执行。在操作系统层面,多任务和多进程是通过分配不同的内存空间来实现的,而线程则共享同一进程的内存,这...

    java多线程并发编程知识导图笔记.xmind

    java多线程并发编程知识导图笔记.xmind

    java线程与并发编程

    java线程与并发编程是java并发编程的盛典,绝对高清版

    java多线程并发实战和源码

    Java多线程并发实战与源码分析是Java开发中至关重要的一部分,它涉及到程序性能优化、系统资源高效利用以及复杂逻辑的正确同步。本书主要聚焦于Java多线程的基础理论和实际应用,虽然书中实例和源码相对较少,但仍然...

    java多线程并发控制[参照].pdf

    java多线程并发控制[参照].pdf

    java多线程并发编程例子

    Java多线程并发编程是Java开发中的重要领域,特别是在服务器端和高并发应用中不可或缺。`java.util.concurrent`包提供了丰富的工具类,帮助开发者更好地管理线程和优化并发性能。以下将详细介绍标题和描述中涉及的...

    java socket 多线程并发控制 hibernate mysql

    本项目聚焦于使用Java的Socket进行多线程并发控制,并结合Hibernate ORM框架与MySQL数据库进行数据存储。下面将详细阐述这些技术及其应用。 首先,Java Socket是Java提供的用于实现网络上不同计算机间进程通信的...

    Java多线程与并发库高级应用

    并发库高级应用\多线程\Java

    JAVA并发多线程的面试问题及答案-java多线程并发面试题.docx

    线程间交互是 Java 多线程并发编程中非常重要的一方面。面试官通常会问一些相关的问题,以检测候选者的基础知识和实际编程能力。 * wait 和 sleep 方法的不同? 这个问题是检测候选者对 wait 和 sleep 方法的理解和...

Global site tag (gtag.js) - Google Analytics