java大神看过来,关于java多线程并发和定时器的问题?。。?/h2>threadCount 加上锁就行了 要么是大于30 死循环了 要么是小于0死循环了 。大于30那边可能性比较小,小于0那边可能性比较大 。
可以在这2个地方打印日志验证一下
Java并发编程:如何创建线程,进程在java中如果要创建线程的话,一般有两种方式:1)继承Thread类;2)实现Runnable接口 。
1.继承Thread类
继承Thread类的话,必须重写run方法,在run方法中定义需要执行的任务 。
123456789101112
class MyThread extends Thread{private static int num = 0;public MyThread(){num;}@Overridepublic void run() {System.out.println("主动创建的第" num "个线程");}}
创建好了自己的线程类之后,就可以创建线程对象了,然后通过start()方法去启动线程 。注意 , 不是调用run()方法启动线程,run方法中只是定义需要执行的任务 , 如果调用run方法,即相当于在主线程中执行run方法,跟普通的方法调用没有任何区别,此时并不会创建一个新的线程来执行定义的任务 。
1234567891011121314151617181920
public class Test {public static void main(String[] args){MyThread thread = new MyThread();thread.start();}}class MyThread extends Thread{private static int num = 0;public MyThread(){num;}@Overridepublic void run() {System.out.println("主动创建的第" num "个线程");}}
在上面代码中 , 通过调用start()方法,就会创建一个新的线程了 。为了分清start()方法调用和run()方法调用的区别,请看下面一个例子:
1234567891011121314151617181920212223
public class Test {public static void main(String[] args){System.out.println("主线程ID:" Thread.currentThread().getId());MyThread thread1 = new MyThread("thread1");thread1.start();MyThread thread2 = new MyThread("thread2");thread2.run();}}class MyThread extends Thread{private String name;public MyThread(String name){this.name = name;}@Overridepublic void run() {System.out.println("name:" name " 子线程ID:" Thread.currentThread().getId());}
java并发包源码怎么读1. 各种同步控制工具的使用
1.1 ReentrantLock
ReentrantLock感觉上是synchronized的增强版,synchronized的特点是使用简单,一切交给JVM去处理,但是功能上是比较薄弱的 。在JDK1.5之前,ReentrantLock的性能要好于synchronized , 由于对JVM进行了优化,现在的JDK版本中,两者性能是不相上下的 。如果是简单的实现,不要刻意去使用ReentrantLock 。
相比于synchronized,ReentrantLock在功能上更加丰富 , 它具有可重入、可中断、可限时、公平锁等特点 。
首先我们通过一个例子来说明ReentrantLock最初步的用法:
package test;
import java.util.concurrent.locks.ReentrantLock;public class Test implements Runnable{ public static ReentrantLock lock = new ReentrantLock(); public static int i = 0;
@Override public void run() {for (int j = 0; j10000000; j)
{lock.lock();try
{
i;
}finally
{lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
Test test = new Test();
Thread t1 = new Thread(test);
Thread t2 = new Thread(test);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
有两个线程都对i进行操作,为了保证线程安全,使用了 ReentrantLock , 从用法上可以看出 , 与 synchronized相比,ReentrantLock就稍微复杂一点 。因为必须在finally中进行解锁操作,如果不在 finally解锁,有可能代码出现异常锁没被释放,而synchronized是由JVM来释放锁 。
那么ReentrantLock到底有哪些优秀的特点呢?
1.1.1 可重入
单线程可以重复进入,但要重复退出
lock.lock();
lock.lock();try{
i;
}
finally{
lock.unlock();
lock.unlock();
}
由于ReentrantLock是重入锁,所以可以反复得到相同的一把锁,它有一个与锁相关的获取计数器 , 如果拥有锁的某个线程再次得到锁 , 那么获取计数器就加1 , 然后锁需要被释放两次才能获得真正释放(重入锁) 。这模仿了 synchronized 的语义;如果线程进入由线程已经拥有的监控器保护的 synchronized 块 , 就允许线程继续进行 , 当线程退出第二个(或者后续) synchronized 块的时候,不释放锁,只有线程退出它进入的监控器保护的第一个synchronized 块时,才释放锁 。
public class Child extends Father implements Runnable{final static Child child = new Child();//为了保证锁唯一
public static void main(String[] args) {for (int i = 0; i50; i) {new Thread(child).start();
}
}
public synchronized void doSomething() {
System.out.println("1child.doSomething()");
doAnotherThing(); // 调用自己类中其他的synchronized方法
}
private synchronized void doAnotherThing() {super.doSomething(); // 调用父类的synchronized方法
System.out.println("3child.doAnotherThing()");
}
@Override
public void run() {
child.doSomething();
}
}class Father {public synchronized void doSomething() {
System.out.println("2father.doSomething()");
}
}
我们可以看到一个线程进入不同的 synchronized方法,是不会释放之前得到的锁的 。所以输出还是顺序输出 。所以synchronized也是重入锁
输出:
1child.doSomething()
2father.doSomething()
3child.doAnotherThing()
1child.doSomething()
2father.doSomething()
3child.doAnotherThing()
1child.doSomething()
2father.doSomething()
3child.doAnotherThing()
...
1.1.2.可中断
与synchronized不同的是 , ReentrantLock对中断是有响应的 。中断相关知识查看[高并发Java 二] 多线程基础
普通的lock.lock()是不能响应中断的,lock.lockInterruptibly()能够响应中断 。
我们模拟出一个死锁现场,然后用中断来处理死锁
package test;import java.lang.management.ManagementFactory;import java.lang.management.ThreadInfo;import java.lang.management.ThreadMXBean;import java.util.concurrent.locks.ReentrantLock;public class Test implements Runnable{ public static ReentrantLock lock1 = new ReentrantLock(); public static ReentrantLock lock2 = new ReentrantLock(); int lock; public Test(int lock)
{this.lock = lock;
} @Override
public void run()
{try
{if (lock == 1)
{
lock1.lockInterruptibly();try
{
Thread.sleep(500);
}catch (Exception e)
{// TODO: handle exception
}
lock2.lockInterruptibly();
}else
{
lock2.lockInterruptibly();try
{
Thread.sleep(500);
}catch (Exception e)
{// TODO: handle exception
}
lock1.lockInterruptibly();
}
}catch (Exception e)
{// TODO: handle exception
}finally
{if (lock1.isHeldByCurrentThread())
{
lock1.unlock();
}if (lock2.isHeldByCurrentThread())
{
lock2.unlock();
}
System.out.println(Thread.currentThread().getId()":线程退出");
}
} public static void main(String[] args) throws InterruptedException {
Test t1 = new Test(1);
Test t2 = new Test(2);
Thread thread1 = new Thread(t1);
Thread thread2 = new Thread(t2);
thread1.start();
thread2.start();
Thread.sleep(1000);//DeadlockChecker.check();
} static class DeadlockChecker
{private final static ThreadMXBean mbean = ManagementFactory
.getThreadMXBean();final static Runnable deadlockChecker = new Runnable()
{@Override
public void run()
{// TODO Auto-generated method stub
while (true)
{long[] deadlockedThreadIds = mbean.findDeadlockedThreads();if (deadlockedThreadIds != null)
{
ThreadInfo[] threadInfos = mbean.getThreadInfo(deadlockedThreadIds);for (Thread t : Thread.getAllStackTraces().keySet())
{for (int i = 0; ithreadInfos.length; i)
{if(t.getId() == threadInfos[i].getThreadId())
{
t.interrupt();
}
}
}
}try
{
Thread.sleep(5000);
}catch (Exception e)
{// TODO: handle exception
}
}
}
};
public static void check()
{
Thread t = new Thread(deadlockChecker);
t.setDaemon(true);
t.start();
}
}
}
上述代码有可能会发生死锁,线程1得到lock1,线程2得到lock2,然后彼此又想获得对方的锁 。
我们用jstack查看运行上述代码后的情况
的确发现了一个死锁 。
DeadlockChecker.check();方法用来检测死锁,然后把死锁的线程中断 。中断后,线程正常退出 。
1.1.3.可限时
超时不能获得锁,就返回false,不会永久等待构成死锁
使用lock.tryLock(long timeout, TimeUnit unit)来实现可限时锁 , 参数为时间和单位 。
举个例子来说明下可限时:
package test;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.ReentrantLock;public class Test implements Runnable{ public static ReentrantLock lock = new ReentrantLock(); @Override
public void run()
{try
{if (lock.tryLock(5, TimeUnit.SECONDS))
{
Thread.sleep(6000);
}else
{
System.out.println("get lock failed");
}
}catch (Exception e)
{
}finally
{if (lock.isHeldByCurrentThread())
{
lock.unlock();
}
}
}
public static void main(String[] args)
{
Test t = new Test();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();
t2.start();
}
}
使用两个线程来争夺一把锁 , 当某个线程获得锁后 , sleep6秒 , 每个线程都只尝试5秒去获得锁 。
所以必定有一个线程无法获得锁 。无法获得后就直接退出了 。
输出:
【java并发器代码 java并发的时候常用的处理方式】get lock failed
1.1.4.公平锁
使用方式:
public ReentrantLock(boolean fair) public static ReentrantLock fairLock = new ReentrantLock(true);
一般意义上的锁是不公平的,不一定先来的线程能先得到锁,后来的线程就后得到锁 。不公平的锁可能会产生饥饿现象 。
公平锁的意思就是,这个锁能保证线程是先来的先得到锁 。虽然公平锁不会产生饥饿现象 , 但是公平锁的性能会比非公平锁差很多 。
1.2 Condition
Condition与ReentrantLock的关系就类似于synchronized与Object.wait()/signal()
await()方法会使当前线程等待 , 同时释放当前锁,当其他线程中使用signal()时或者signalAll()方法时,线 程会重新获得锁并继续执行 。或者当线程被中断时,也能跳出等待 。这和Object.wait()方法很相似 。
awaitUninterruptibly()方法与await()方法基本相同 , 但是它并不会再等待过程中响应中断 。singal()方法用于唤醒一个在等待中的线程 。相对的singalAll()方法会唤醒所有在等待中的线程 。这和Obejct.notify()方法很类似 。
这里就不再详细介绍了 。举个例子来说明:
package test;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;public class Test implements Runnable{ public static ReentrantLock lock = new ReentrantLock(); public static Condition condition = lock.newCondition();
@Override public void run() {try
{lock.lock();
condition.await();
System.out.println("Thread is going on");
}catch (Exception e)
{
e.printStackTrace();
}finally
{lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
Test t = new Test();
Thread thread = new Thread(t);
thread.start();
Thread.sleep(2000);
lock.lock();
condition.signal();lock.unlock();
}
}
上述例子很简单 , 让一个线程await住,让主线程去唤醒它 。condition.await()/signal只能在得到锁以后使用 。
1.3.Semaphore
对于锁来说,它是互斥的排他的 。意思就是,只要我获得了锁,没人能再获得了 。
而对于Semaphore来说 , 它允许多个线程同时进入临界区 。可以认为它是一个共享锁,但是共享的额度是有限制的 , 额度用完了,其他没有拿到额度的线程还是要阻塞在临界区外 。当额度为1时,就相等于lock
下面举个例子:
package test;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;public class Test implements Runnable{ final Semaphore semaphore = new Semaphore(5); @Override
public void run()
{try
{
semaphore.acquire();
Thread.sleep(2000);
System.out.println(Thread.currentThread().getId()" done");
}catch (Exception e)
{
e.printStackTrace();
}finally {
semaphore.release();
}
}
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(20);final Test t = new Test();for (int i = 0; i20; i)
{
executorService.submit(t);
}
}
}
有一个20个线程的线程池,每个线程都去 Semaphore的许可,Semaphore的许可只有5个,运行后可以看到 , 5个一批,一批一批地输出 。
当然一个线程也可以一次申请多个许可
public void acquire(int permits) throws InterruptedException
1.4 ReadWriteLock
ReadWriteLock是区分功能的锁 。读和写是两种不同的功能 , 读-读不互斥,读-写互斥,写-写互斥 。
这样的设计是并发量提高了,又保证了数据安全 。
使用方式:
private static ReentrantReadWriteLock readWriteLock=new ReentrantReadWriteLock();
private static Lock readLock = readWriteLock.readLock();
private static Lock writeLock = readWriteLock.writeLock();
详细例子可以查看 Java实现生产者消费者问题与读者写者问题,这里就不展开了 。
1.5 CountDownLatch
倒数计时器
一种典型的场景就是火箭发射 。在火箭发射前,为了保证万无一失,往往还要进行各项设备、仪器的检查 。只有等所有检查完毕后,引擎才能点火 。这种场景就非常适合使用CountDownLatch 。它可以使得点火线程
, 等待所有检查线程全部完工后 , 再执行
使用方式:
static final CountDownLatch end = new CountDownLatch(10);
end.countDown();
end.await();
示意图:
一个简单的例子:
package test;import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class Test implements Runnable{ static final CountDownLatch countDownLatch = new CountDownLatch(10); static final Test t = new Test(); @Override
public void run()
{try
{
Thread.sleep(2000);
System.out.println("complete");
countDownLatch.countDown();
}catch (Exception e)
{
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(10);for (int i = 0; i10; i)
{
executorService.execute(t);
}
countDownLatch.await();
System.out.println("end");
executorService.shutdown();
}
}
主线程必须等待10个线程全部执行完才会输出"end" 。
1.6 CyclicBarrier
和CountDownLatch相似,也是等待某些线程都做完以后再执行 。与CountDownLatch区别在于这个计数器可以反复使用 。比如 , 假设我们将计数器设置为10 。那么凑齐第一批1 0个线程后,计数器就会归零,然后接着凑齐下一批10个线程
使用方式:
public CyclicBarrier(int parties, Runnable barrierAction) barrierAction就是当计数器一次计数完成后,系统会执行的动作await()
示意图:
下面举个例子:
package test;import java.util.concurrent.CyclicBarrier;public class Test implements Runnable{ private String soldier; private final CyclicBarrier cyclic; public Test(String soldier, CyclicBarrier cyclic)
{this.soldier = soldier;this.cyclic = cyclic;
} @Override
public void run()
{try
{//等待所有士兵到齐
cyclic.await();
dowork();//等待所有士兵完成工作
cyclic.await();
}catch (Exception e)
{// TODO Auto-generated catch block
e.printStackTrace();
}
} private void dowork()
{// TODO Auto-generated method stub
try
{
Thread.sleep(3000);
}catch (Exception e)
{// TODO: handle exception
}
System.out.println(soldier": done");
} public static class BarrierRun implements Runnable
{boolean flag;int n;public BarrierRun(boolean flag, int n)
{super();this.flag = flag;this.n = n;
}@Override
public void run()
{if (flag)
{
System.out.println(n"个任务完成");
}else
{
System.out.println(n"个集合完成");
flag = true;
}
}
} public static void main(String[] args)
{final int n = 10;
Thread[] threads = new Thread[n];boolean flag = false;
CyclicBarrier barrier = new CyclicBarrier(n, new BarrierRun(flag, n));
System.out.println("集合");for (int i = 0; in; i)
{
System.out.println(i"报道");
threads[i] = new Thread(new Test("士兵"i, barrier));
threads[i].start();
}
}
}
打印结果:
集合
士兵5: done士兵7: done士兵8: done士兵3: done士兵4: done士兵1: done士兵6: done士兵2: done士兵0: done士兵9: done10个任务完成
1.7 LockSupport
提供线程阻塞原语
和suspend类似
LockSupport.park();
LockSupport.unpark(t1);
与suspend相比 不容易引起线程冻结
LockSupport的思想呢,和 Semaphore有点相似 , 内部有一个许可,park的时候拿掉这个许可,unpark的时候申请这个许可 。所以如果unpark在park之前,是不会发生线程冻结的 。
下面的代码是[高并发Java 二] 多线程基础中suspend示例代码,在使用suspend时会发生死锁 。
而使用 LockSupport则不会发生死锁 。
另外
park()能够响应中断,但不抛出异常 。中断响应的结果是 , park()函数的返回,可以从Thread.interrupted()得到中断标志 。
在JDK当中有大量地方使用到了park,当然LockSupport的实现也是使用unsafe.park()来实现的 。
public static void park() {unsafe.park(false, 0L);
}
1.8 ReentrantLock 的实现
下面来介绍下ReentrantLock的实现,ReentrantLock的实现主要由3部分组成:
CAS状态
等待队列
park()
ReentrantLock的父类中会有一个state变量来表示同步的状态
/**
* The synchronization state.
*/
private volatile int state;
通过CAS操作来设置state来获取锁,如果设置成了1,则将锁的持有者给当前线程
final void lock() {if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());else
acquire(1);
}
如果拿锁不成功 , 则会做一个申请
public final void acquire(int arg) {if (!tryAcquire(arg)
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
首先,再去申请下试试看tryAcquire,因为此时可能另一个线程已经释放了锁 。
如果还是没有申请到锁,就addWaiter,意思是把自己加到等待队列中去
其间还会有多次尝试去申请锁,如果还是申请不到,就会被挂起
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);return Thread.interrupted();
}
同理,如果在unlock操作中 , 就是释放了锁,然后unpark,这里就不具体讲了 。
2. 并发容器及典型源码分析
2.1 ConcurrentHashMap
我们知道HashMap不是一个线程安全的容器,最简单的方式使HashMap变成线程安全就是使用Collections.synchronizedMap,它是对HashMap的一个包装
public static Map m=Collections.synchronizedMap(new HashMap());
同理对于List , Set也提供了相似方法 。
但是这种方式只适合于并发量比较小的情况 。
我们来看下synchronizedMap的实现
它会将HashMap包装在里面,然后将HashMap的每个操作都加上synchronized 。
由于每个方法都是获取同一把锁(mutex),这就意味着,put和remove等操作是互斥的,大大减少了并发量 。
下面来看下ConcurrentHashMap是如何实现的
在 ConcurrentHashMap内部有一个Segment段,它将大的HashMap切分成若干个段(小的HashMap) , 然后让数据在每一段上Hash,这样多个线程在不同段上的Hash操作一定是线程安全的,所以只需要同步同一个段上的线程就可以了,这样实现了锁的分离,大大增加了并发量 。
在使用ConcurrentHashMap.size时会比较麻烦,因为它要统计每个段的数据和,在这个时候,要把每一个段都加上锁,然后再做数据统计 。这个就是把锁分离后的小小弊端,但是size方法应该是不会被高频率调用的方法 。
在实现上,不使用synchronized和lock.lock而是尽量使用trylock , 同时在HashMap的实现上,也做了一点优化 。这里就不提了 。
2.2 BlockingQueue
BlockingQueue不是一个高性能的容器 。但是它是一个非常好的共享数据的容器 。是典型的生产者和消费者的实现 。
java并发常识1.java并发编程是什么
1,保证线程安全的三种方法: a , 不要跨线程访问共享变量b,使共享变量是final类型的c, 将共享变量的操作加上同步 2,一开始就将类设计成线程安全的,比在后期重新修复它,更容易 。
3, 编写多线程程序, 首先保证它是正确的,其次再考虑性能 。4 , 无状态或只读对象永远是线程安全的 。
5,不要将一个共享变量 *** 在多线程环境下(无同步或不可变性保护) 6,多线程环境下的延迟加载需要同步的保护,因为延迟加载会造成对象重复实例化 7,对于volatile声明的数值类型变量进行运算,往往是不安全的(volatile只能保证可见性,不能保证原子性) 。详见volatile原理与技巧中 , 脏数据问题讨论 。
8, 当一个线程请求获得它自己占有的锁时(同一把锁的嵌套使用) , 我们称该锁为可重入锁 。在jdk1 。
5并发包中,提供了可重入锁的java实现-ReentrantLock 。9,每个共享变量,都应该由一个唯一确定的锁保护 。
创建与变量相同数目的ReentrantLock,使他们负责每个变量的线程安全 。10 , 虽然缩小同步块的范围,可以提升系统性能 。
但在保证原子性的情况下,不可将原子操作分解成多个synchronized块 。11,在没有同步的情况下,编译器与处理器运行时的指令执行顺序可能完全出乎意料 。
原因是, 编译器或处理器为了优化自身执行效率 , 而对指令进行了的重排序(reordering) 。12,当一个线程在没有同步的情况下读取变量, 它可能会得到一个过期值 , 但是至少它可以看到那个线程在当时设定的一个真实数值 。
而不是凭空而来的值 。这种安全保证,称之为最低限的安全性(out-of-thin-air safety) 在开发并发应用程序时,有时为了大幅度提高系统的吞吐量与性能, 会采用这种无保障的做法 。
但是针对 , 数值的运算,仍旧是被否决的 。13, volatile变量,只能保证可见性 , 无法保证原子性 。
14,某些耗时较长的网络操作或IO,确保执行时,不要占有锁 。15,发布(publish)对象 , 指的是使它能够被当前范围之外的代码所使用 。
(引用传递)对象逸出(escape),指的是一个对象在尚未准备好时将它发布 。原则: 为防止逸出,对象必须要被完全构造完后, 才可以被发布(最好的解决方式是采用同步) this关键字引用对象逸出 例子: 在构造函数中 , 开启线程,并将自身对象this传入线程,造成引用传递 。
而此时,构造函数尚未执行完 , 就会发生对象逸出了 。16,必要时,使用ThreadLocal变量确保线程封闭性(封闭线程往往是比较安全的 , 但一定程度上会造成性能损耗)封闭对象的例子在实际使用过程中,比较常见,例如 hibernate openSessionInView机制, jdbc的connection机制 。
17,单一不可变对象往往是线程安全的(复杂不可变对象需要保证其内部成员变量也是不可变的)良好的多线程编程习惯是: 将所有的域都声明为final , 除非它们是可变的 。
2.Java线程并发协作是什么
线程发生死锁可能性很小 , 即使看似可能发生死锁的代码,在运行时发生死锁的可能性也是小之又小 。
发生死锁的原因一般是两个对象的锁相互等待造成的 。在《Java线程:线程的同步与锁》一文中,简述死锁的概念与简单例子 , 但是所给的例子是不完整的,这里给出一个完整的例子 。
/** * Java线程:并发协作-死锁 * * @author Administrator 2009-11-4 22:06:13 */ public class Test { public static void main(String[] args) { DeadlockRisk dead = new DeadlockRisk(); MyThread t1 = new MyThread(dead, 1, 2); MyThread t2 = new MyThread(dead, 3, 4); MyThread t3 = new MyThread(dead, 5, 6); MyThread t4 = new MyThread(dead, 7, 8); t1 。start(); t2 。
start(); t3 。start(); t4 。
start(); } } class MyThread extends Thread { private DeadlockRisk dead; private int a, b; MyThread(DeadlockRisk dead, int a, int b) { this 。dead = dead; this 。
a = a; this 。b = b; } @Override public void run() { dead 。
read(); dead 。write(a, b); } } class DeadlockRisk { private static class Resource { public int value; } 。
3.如何学习Java高并发
1.学习 *** 并发框架的使用,如ConcurrentHashMAP,CopyOnWriteArrayList/Set等2.几种并发锁的使用以及线程同步与互斥,如ReentainLock,synchronized,Lock,CountDownLatch,Semaphore等3.线程池如Executors,ThreadPoolExecutor等4.Runable,Callable,RescureTask,Future,FutureTask等5.Fork-Join框架以上基本包含完了,如有缺漏请原谅 。
4.并发编程的Java抽象有哪些呢
一、机器和OS级别抽象 (1)冯诺伊曼模型 经典的顺序化计算模型 , 貌似可以保证顺序化一致性 , 但是没有哪个现代的多处理架构会提供顺序一致性 , 冯氏模型只是现代多处理器行为的模糊近似 。
这个计算模型 , 指令或者命令列表改变内存变量直接契合命令编程泛型,它以显式的算法为中心,这和声明式编程泛型有区别 。就并发编程来说,会显著的引入时间概念和状态依赖 所以所谓的函数式编程可以解决其中的部分问题 。
(2)进程和线程 进程抽象运行的程序,是操作系统资源分配的基本单位,是资源cpu,内存,IO的综合抽象 。线程是进程控制流的多重分支 , 它存在于进程里 , 是操作系统调度的基本单位,线程之间同步或者异步执行,共享进程的内存地址空间 。
(3)并发与并行 并发,英文单词是concurrent,是指逻辑上同时发生,有人做过比喻,要完成吃完三个馒头的任务,一个人可以这个馒头咬一口,那个馒头咬一口,这样交替进行,最后吃完三个馒头,这就是并发,因为在三个馒头上同时发生了吃的行为,如果只是吃完一个接着吃另一个,这就不是并发了,是排队,三个馒头如果分给三个人吃,这样的任务完成形式叫并行,英文单词是parallel 。回到计算机概念,并发应该是单CPU时代或者单核时代的说法,这个时候CPU要同时完成多任务,只能用时间片轮转,在逻辑上同时发生,但在物理上是串行的 。
现在大多数计算机都是多核或者多CPU,那么现在的多任务执行方式就是物理上并行的 。为了从物理上支持并发编程,CPU提供了相应的特殊指令,比如原子化的读改写,比较并交换 。
(4)平台内存模型 在可共享内存的多处理器体系结构中,每个处理器都有它自己的缓存,并且周期性的与主存同步 , 为什么呢?因为处理器通过降低一致性来换取性能,这和CAP原理通过降低一致性来获取伸缩性有点类似,所以大量的数据在CPU的寄存器中被计算 , 另外CPU和编译器为了性能还会乱序执行 , 但是CPU会提供存储关卡指令来保证存储的同步,各种平台的内存模型或者同步指令可能不同,所以这里必须介入对内存模型的抽象,JMM就是其中之一 。二、编程模型抽象 (1)基于线程模型 (2)基于Actor模型 (3)基于STM软件事务内存 …… Java体系是一个基于线程模型的本质编程平台,所以我们主要讨论线程模型 。
三、并发单元抽象 大多数并发应用程序都是围绕执行任务进行管理的,任务是抽象,离散的工作单元,所以编写并发程序,首要工作就是提取和分解并行任务 。一旦任务被抽象出来,他们就可以交给并发编程平台去执行,同时在任务抽象还有另一个重要抽象,那就是生命周期,一个任务的开始,结束 , 返回结果,都是生命周期中重要的阶段 。
那么编程平台必须提供有效安全的管理任务生命周期的API 。四、线程模型 线程模型是Java的本质模型,它无所不在,所以Java开发必须搞清楚底层线程调度细节,不搞清楚当然就会有struts1,struts2的原理搞不清楚的基本灾难(比如在struts2的action中塞入状态,把struts2的action配成单例) 。
用线程来抽象并发编程,是比较低级别的抽象,所以难度就大一些,难度级别会根据我们的任务特点有以下几个类别 (1)任务非常独立,不共享,这是最理想的情况 , 编程压力为0 。(2)共享数据,压力开始增大,必须引入锁,Volatile变量,问题有活跃度和性能危险 。
(3)状态依赖,压力再度增大,这时候我们基本上都是求助jdk 提供的同步工具 。五、任务执行 任务是一个抽象体,如果被抽象了出来,下一步就是交给编程平台去执行 , 在Java中,描述任务的一个基本接口是Runnable , 可是这个抽象太有限了 , 它不能返回值和抛受检查异常 , 所以Jdk5 。
0有另外一个高级抽象Callable 。任务的执行在Jdk中也是一个底级别的Thread,线程有好处,但是大量线程就有大大的坏处,所以如果任务量很多我们并不能就创建大量的线程去服务这些任务,那么Jdk5 。
0在任务执行上做了抽象,将任务和任务执行隔离在接口背后,这样我们就可以引入比如线程池的技术来优化执行,优化线程的创建 。任务是有生命周期的,所以Jdk5 。
0提供了Future这个对象来描述对象的生命周期,通过这个future可以取到任务的结果甚至取消任务 。六、锁 当然任务之间共享了数据,那么要保证数据的安全,必须提供一个锁机制来协调状态,锁让数据访问原子,但是引入了串行化,降低了并发度,锁是降低程序伸缩性的原罪,锁是引入上下文切换的主要原罪,锁是引入死锁,活锁,优先级倒置的绝对原罪,但是又不能没有锁,在Java中,锁是一个对象,锁提供原子和内存可见性,Volatile变量提供内存可见性不提供原子,原子变量提供可见性和原子,通过原子变量可以构建无锁算法和无锁数据结构,但是这需要高高手才可以办到 。
5.Java高并发入门要怎么学习
1、如果不使用框架,纯原生Java编写,是需要了解Java并发编程的,主要就是学习Doug Lea开发的那个java.util.concurrent包下面的API;2、如果使用框架,那么我的理解,在代码层面确实不会需要太多的去关注并发问题,反而是由于高并发会给系统造成很大压力 , 要在缓存、数据库操作上要多加考虑 。
3、但是即使是使用框架,在工作中还是会用到多线程,就拿常见的CRUD接口来说,比如一个非常耗时的save接口,有多耗时呢?我们假设整个save执行完要10分钟,所以,在save的时候,就需要采用异步的方式,也就是单独用一个线程去save,然后直接给前端返回200 。
6.Java如何进行并发多连接socket编程呢
Java多个客户端同时连接服务端,在现实生活中用得比较多 。
同时执行多项任务 , 第一想到的当然是多线程了 。下面用多线程来实现并发多连接 。
import java 。。
*; import java 。io 。
*; public class ThreadServer extends Thread { private Socket client; public ThreadServer(Socket c) { this 。client=c; } public void run() { try { BufferedReader in=new BufferedReader(new InputStreamReader(client 。
getInputStream())); PrintWriter out=new PrintWriter(client 。getOutputStream()); Mutil User but can't parallel while (true) { String str=in 。
readLine(); System 。out 。
println(str); out 。println("has receive 。
"); out 。
flush(); if (str 。equals("end")) break; } client 。
close(); } catch (IOException ex) { } finally { } } public static void main(String[] args)throws IOException { ServerSocket server=new ServerSocket(8000); while (true) { transfer location change Single User or Multi User ThreadServer mu=new ThreadServer(server 。accept()); mu 。
start(); } } }J 。
7.如何掌握java多线程,高并发,大数据方面的技能
线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小 。
(线程是cpu调度的最小单位)线程和进程一样分为五个阶段:创建、就绪、运行、阻塞、终止 。多进程是指操作系统能同时运行多个任务(程序) 。
多线程是指在同一程序中有多个顺序流在执行 。在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口.(其实准确来讲,应该有三种,还有一种是实现Callable接口 , 并与Future、线程池结合使用 。
8.java工程师需要掌握哪些知识
1.Core Java , 就是Java基础、JDK的类库 , 很多童鞋都会说,JDK我懂,但是懂还不足够,知其然还要知其所以然 , JDK的源代码写的非常好,要经常查看,对使用频繁的类,比如String , *** 类(List,Map,Set)等数据结构要知道它们的实现,不同的 *** 类有什么区别,然后才能知道在一个具体的场合下使用哪个 *** 类更适合、更高效,这些内容直接看源代码就OK了2.多线程并发编程,现在并发几乎是写服务端程序必须的技术 , 那对Java中的多线程就要有足够的熟悉,包括对象锁机制、synchronized关键字,concurrent包都要非常熟悉,这部分推荐你看看《Java并发编程实践》这本书,讲解的很详细3.I/O,Socket编程 , 首先要熟悉Java中Socket编程,以及I/O包,再深入下去就是Java NIO,再深入下去是操作系统底层的Socket实现 , 了解Windows和Linux中是怎么实现socket的4.JVM的一些知识 , 不需要熟悉,但是需要了解,这是Java的本质 , 可以说是Java的母体, 了解之后眼界会更宽阔,比如Java内存模型(会对理解Java锁、多线程有帮助)、字节码、JVM的模型、各种垃圾收集器以及选择、JVM的执行参数(优化JVM)等等,这些知识在《深入Java虚拟机》这本书中都有详尽的解释 , 或者去oracle网站上查看具体版本的JVM规范.5.一些常用的设计模式 , 比如单例、模板方法、代理、适配器等等,以及在Core Java和一些Java框架里的具体场景的实现,这个可能需要慢慢积累 , 先了解有哪些使用场景,见得多了,自己就自然而然会去用 。
6.常用数据库(Oracle、MySQL等)、SQL语句以及一般的优化7.JavaWeb开发的框架,比如Spring、iBatis等框架 , 同样他们的原理才是最重要的 , 至少要知道他们的大致原理 。8.其他一些有名的用的比较多的开源框架和包 , ty网络框架 , Apache mon的N多包 , Google的Guava等等,也可以经常去Github上找一些代码看看 。
暂时想到的就这么多吧,1-4条是Java基?。?全部的这些知识没有一定的时间积累是很难搞懂的,但是了解了之后会对Java有个彻底的了解 , 5和6是需要学习的额外技术,7-8是都是基于1-4条的,正所谓万变不离其宗,前4条就是Java的灵魂所在,希望能对你有所帮助9.(补充)学会使用Git 。如果你还在用SVN的话,赶紧投入Git的怀抱吧 。
9.java 多线程的并发到底是什么意思
一、多线程1、操作系统有两个容易混淆的概念,进程和线程 。
进程:一个计算机程序的运行实例,包含了需要执行的指令;有自己的独立地址空间 , 包含程序内容和数据;不同进程的地址空间是互相隔离的;进程拥有各种资源和状态信息,包括打开的文件、子进程和信号处理 。线程:表示程序的执行流程,是CPU调度执行的基本单位;线程有自己的程序计数器、寄存器、堆栈和帧 。
同一进程中的线程共用相同的地址空间,同时共享进进程锁拥有的内存和其他资源 。2、Java标准库提供了进程和线程相关的API , 进程主要包括表示进程的java.lang.Process类和创建进程的java.lang.ProcessBuilder类;表示线程的是java.lang.Thread类,在虚拟机启动之后,通常只有Java类的main方法这个普通线程运行 , 运行时可以创建和启动新的线程;还有一类守护线程(damon thread),守护线程在后台运行,提供程序运行时所需的服务 。
当虚拟机中运行的所有线程都是守护线程时,虚拟机终止运行 。3、线程间的可见性:一个线程对进程 *** 享的数据的修改 , 是否对另一个线程可见可见性问题:a、CPU采用时间片轮转等不同算法来对线程进行调度[java] view plaincopypublic class IdGenerator{ private int value = https://www.04ip.com/post/0; public int getNext(){ return value; } } 对于IdGenerator的getNext()方法,在多线程下不能保证返回值是不重复的:各个线程之间相互竞争CPU时间来获取运行机会,CPU切换可能发生在执行间隙 。
以上代码getNext()的指令序列:CPU切换可能发生在7条指令之间,多个getNext的指令交织在一起 。
java代码的高并发怎么用public class Test {
public static void main(String[] args) {
int count = 1000;
ExecutorService executorService = Executors.newFixedThreadPool(count);
for (int i = 0; icount; i)
executorService.execute(new Test().new Task());
executorService.shutdown();
while (!executorService.isTerminated()) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Task implements Runnable {
@Override
public void run() {
try {
// 测试内容
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
如果要实现真正的并发同时执行,可通过CyclicBarrier来控制 。
public class Test {
public static void main(String[] args) {
int count = 1000;
CyclicBarrier cyclicBarrier = new CyclicBarrier(count);
ExecutorService executorService = Executors.newFixedThreadPool(count);
for (int i = 0; icount; i)
executorService.execute(new Test().new Task(cyclicBarrier));
executorService.shutdown();
while (!executorService.isTerminated()) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Task implements Runnable {
private CyclicBarrier cyclicBarrier;
public Task(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
try {
// 等待所有任务准备就绪
cyclicBarrier.await();
// 测试内容
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
关于java并发器代码和java并发的时候常用的处理方式的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站 。
推荐阅读
- 快手直播如何关联直播伴侣,快手直播伴侣怎么添加直播内容
- 电商如何控制好库存量,电子商务库存量的控制方法有哪些
- 苹果电脑怎么没有型号显示,苹果电脑型号在哪里找
- 全新赛车竞速游戏,赛车竞速游戏排行榜pc
- linux命令删除一块 linux 删除命令详解
- 电视猫怎么安装到熊猫电视,如何在电视猫里安装电视直播软件
- jq设置css动态样式数值,js动态设置css样式
- .net如何传参数的,net传递参数的方法
- c语言有哪几种函数 c语言中函数都有哪些