并发:这里先说下进程和线程的区别 :
一个程序至少需要一个进程一个线程,进程是独立于内存 ,线程是共享于内存 ,并发性高 也就是说 线程只能是在应用中存在。
并发性在程序里指多个线程同时访问,然java是通过时间片化,实现多线程的 也就是并发 。
同步
线程同步 是指一个线程对象同一时间在同一个方法里执行一次
买票问题 :首先票是唯一的 而买票窗口是N个 如果不同步,那么很有可能一张票卖给两个人,解决这个问题 就是在销售票时 后面的线程进入阻塞状态,等前面的线程结束 释放之后 再进行买票 ` class Threadss implements Runnable {
private int a=6666;
public void run(){
for (int i = 0; i <100000; i++) {
if(a>0){
System.out.println("售票编号 "+a--);
}
}
}
}`
public static void main(String[] args) {
Threadss a=new Threadss();
Threadss b=new Threadss();
Threadss c=new Threadss();
a.run();
b.run();
/*b.run();
c.run();*/
那么什么是阻塞呢?这里我们要必须知道一个问题 那就是对象监视器 monitor 很多地方称为锁 java规定每个对象都有一个锁 ,而且这个锁只有在同步块里才能被正确使用,
synchronized 里面 :锁 只能有被一个线程占用,后面不管有多个,都只能等待,只有该线程使用完 才能释放 ,也有这样一种情况 。例如有一个同步方法 method(); 里面有两个实例 a b 同一时刻a.method() 和b,method() 不冲突 都能完美的调用
所以买票的逻辑在同步块里实现 那么就不会出现一张票两个人的问题
synchronized特点:
1、放方法名前是同步方法 放在块前是同步块
2、当作为块时不能放在if 后面。
锁和同步时注意的
(1)只能同步方法 不能同步变量和类
(2)同步方法所在的类 可以有非同步的方法 程序需要同步时就加synchronized
(3)如果一个线程拥有同步和非同步方法,则非同步方法可以被多个线程自由访问而不受锁限制
(4)线程可以获得多个锁,一个对象的同步方法里面调用另一个对象的同步方法,则获得两个对象的监视器
(5)同步损坏并发性, 同步不仅同步某个方法,还可以同步方法里的末以块
(6)同步静态的方法,则需要把整个类都加上锁 synchronized
wait notify() notifyAll()的使用
wait()
使本线程挂起 挂起的对象将释放montor ,只有其他线程使用notify 和 notifyAll 才能被唤醒使用
notify()
是随机唤醒一个线程
notifyAll()
唤醒所有该对象的沉睡线程,唤起的线程会继续争夺monitor的占有权 最终会有一个占有 其他线程继续等待
下面讨论一个典型问题 生产者和消费者模式
为什么要使用生产者和消费者模式
在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式
什么是生产者消费者模式
这里要引用阻塞队列 ,当生产者生成数据时放入阻塞队列里,消费者从阻塞队列里拿数据,而不找生产者拿数据从阻塞缓冲区里拿数据
生成者和消费者是解决二者之间阻抗效率问题,耦合只是附带的
实例
一个馒头店,厨师生产馒头,放到篮子里,客人从里面拿然后吃掉,当篮子满时 厨师让客人来吃,当篮子空时 让厨师生产
- 生产的物品馒头
package org.com.action;
/**
* 生产的数据 例如馒头
* @author wangfeng
*
*/
public class Mantou {
private int index;
//有参构造方法
public Mantou(int index){
this.index=index;
}
//重写toString 输出
public String toString(){
return "Mantou--"+index;
}
2、篮子
package org.com.action;
public class Basket {
private int i=0; //表示装第几个馒头
private Mantou[] mantou=new Mantou[6]; //篮子的数量
//生成者
public synchronized void pro(Mantou m){
//这里当篮子满时提示客人来吃
while(i==mantou.length){
try {
System.out.println("篮子满了");
this.wait(); //线程暂停,等待唤醒
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"生成"+m.toString());
this.notify(); //生产完,唤醒线程
mantou[i]=m; //把馒头塞进篮子里
i++;
}
//消费者
public synchronized Mantou con(){
while(i==0){
try {
System.out.println("篮子空");
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Mantou is=mantou[--i];
System.out.println(Thread.currentThread().getName()+"消费"+is.toString());
this.notify();
return is;
}
}
3 厨师
package org.com.action;
/**
* 生产者
* @author wangfeng
*
*/
public class Produce implements Runnable {
private Basket b;
public Produce(Basket b){
this.b=b;
}
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i <20; i++) {
Mantou m=new Mantou(i);
b.pro(m);
try {
Thread.sleep(500);//阻塞线程
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
4 消费者
package org.com.action;
public class Consumer implements Runnable {
private Basket b;
public Consumer(Basket b){
this.b=b;
}
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 20; i++) {
Mantou m=b.con();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
5 mian
package org.com.action;
public class ThreeClass {
public static void main(String[] args) {
Basket b=new Basket();
new Thread(new Produce(b)).start();
new Thread(new Consumer(b)).start();
}
}
本文深入探讨Java中的进程与线程的区别、并发性及线程同步机制,通过具体示例解析synchronized关键字的使用方法及其特性。并介绍了生产者消费者模式在解决多线程间数据共享问题的应用。

被折叠的 条评论
为什么被折叠?



