读书人

java并发编程二

发布时间: 2012-11-01 11:11:31 作者: rapoo

java并发编程2

线程安全
调用某函数操作某对象,该对象暂时处于不可用状态,等到操作完成才能回到可用状态。
其他线程企图访问一个不可用状态的对象,该对象不能正确响应而产生无法预料的结果,线程安全的核心问题就是避免这种情况。

servlet的线程安全性
servlet/jsp默认是使用多线程模式执行的。
无状态的servlet、有状态的servlet(含有类实例变量)
解决线程不安全性:
1、取消servlet的类实例变量,编程无状态的servlet
2、对共享数据进行同步操作,使用synchronized关键字保证一次只有一个线程访问被保护的区段。

public class ConcurrentServlet extends HttpServlet {    private static final long serialVersionUID = 1L;    //这样定义成类实例变量就是有状态的servlet    //int result=0;    public ConcurrentServlet() {        super();    }    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        String s1 = request.getParameter("num1");        String s2 = request.getParameter("num2");        int result=0; //这样定义就是无状态servlet        if(s1!=null && s2!=null) {            result = Integer.parseInt(s1) * Integer.parseInt(s2);        }        try {            Thread.sleep(5000);        } catch (InterruptedException e) {            e.printStackTrace();        }        PrintWriter out = response.getWriter();        out.println(result);        out.close();    }    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        doGet(request, response);    }}public class Concurrent2Servlet extends HttpServlet {    private static final long serialVersionUID = 1L;    int result=0;    public Concurrent2Servlet() {        super();    }    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        String s1 = request.getParameter("num1");        String s2 = request.getParameter("num2");        synchronized (this) {            if(s1!=null && s2!=null) {                result = Integer.parseInt(s1) * Integer.parseInt(s2);            }            try {                Thread.sleep(5000);            } catch (InterruptedException e) {                e.printStackTrace();            }            PrintWriter out = response.getWriter();            out.println(result);            out.close();        }    }    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        doGet(request, response);    }}
?


同步和互斥
线程干扰

public class BankAccount {    private int number;    private int balance;    public BankAccount(int number, int balance){        this.number = number;        this.balance = balance;    }    public void deposit(int amount){        balance = balance + amount;    }    public void withdraw(int amount){        balance = balance - amount;    }    public int getBalance() {        return balance;    }    static class Depositer implements Runnable{        BankAccount account;        int amount;        public Depositer(BankAccount account, int amount){            this.account = account;            this.amount = amount;        }        @Override        public void run() {            for(int i=0; i<10000; i++){                account.deposit(amount);            }        }    }    static class Withdrawer implements Runnable{        BankAccount account;        int amount;        public Withdrawer(BankAccount account, int amount){            this.account = account;            this.amount = amount;        }        @Override        public void run() {            for(int i=0; i<10000; i++){                account.withdraw(amount);            }        }    }    public static void main(String[] args) throws InterruptedException {        BankAccount a = new BankAccount(1, 1000);        Thread t1 = new Thread(new Depositer(a, 100), "depositer");        Thread t2 = new Thread(new Withdrawer(a, 100), "withdrawer");        t1.start();        t2.start();        t1.join();        t2.join();        System.out.println(a.getBalance());    }}

?

同步
当两个线程需要使用同一个对象时,存在交叉操作破坏数据独立性的可能,同步可以避免这种线程干扰。
java提供synchronized关键字来支持内在锁
1、同步方法中的锁

public synchronized void deposit(int amount){        balance = balance + amount;}public synchronized void withdraw(int amount){        balance = balance - amount;}

线程调用同步方法时自动获得这个方法所在对象的内在锁,发放返回时释放,发生未捕获的异常时也会释放。
2、同步语句

public void deposit(int amount){    synchronized(this){        balance = balance + amount;    }}public void withdraw(int amount){    synchronized(this){        balance = balance - amount;    }}

同步语句需要制定提供锁的对象
3、同步类
synchronized修饰类,该类的所有方法都是同步方法。
4、可重入同步
不太理解

同步与volatile
java提供了一种同步机制,不提供对锁的独占访问,同样可以确保对变量的每个读取操作都返回最近写入的值,这种机制就是只使用volatile变量。

活性
死锁、饿锁、活锁
死锁,多个线程竞争共享资源,每个线程都被阻塞,不能结束,进入永远等待状态。
死锁案例,哲学家用餐问题。
饿锁,共享资源被贪婪线程长期占用,其他线程不能获取共享资源,不能继续工作。
活锁,线程没有被锁定,只是忙于互相响应,以至不能恢复工作。

ThreadLocal变量
ThreadLocal是Thread的局部变量,ThreadLocal为每个使用该变量的线程提供独立的副本,

public class SequenceNumber {    //匿名子类创建ThreadLocal变量    private static ThreadLocal<Integer> seq = new ThreadLocal<Integer>(){        public Integer initialValue() { //覆盖初始化方法            return 0;        }    };    public Integer getNextNumber(){        seq.set(seq.get()+1);        return seq.get();    }    private static class TestClient extends Thread {        private SequenceNumber sn;        public TestClient(SequenceNumber sn){            this.sn = sn;        }        public void run() {            for(int i=0; i<3; i++) {                System.out.println("Thread["+Thread.currentThread().getName()                        +"] sn["+sn.getNextNumber()+"]");            }        }    }    public static void main(String[] args) {        SequenceNumber sn = new SequenceNumber();        TestClient t1 = new TestClient(sn);        TestClient t2 = new TestClient(sn);        TestClient t3 = new TestClient(sn);        t1.start();        t2.start();        t3.start();    }}

ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题,但是:
同步机制使用‘以时间换空间’的方式,提供一份变量,让不同的线程排队访问;
ThreadLocal使用‘以空间换时间’的方式,为每个线程提供一份变量,同时访问互不影响。

高级并发对象
java.lang.concurrent
Lock对象、执行器、并发集合、原子变量、同步器。

读书人网 >编程

热点推荐