线程的同步

来源:互联网 发布:2017双色球算法必中6红 编辑:程序博客网 时间:2024/06/09 13:45
线程安全:

       在实际的开发中,使用到多线程的情况往往会很多,比如说我们最常遇到的火车站售票系统,我们可以以此为例来说明。

       在通常的单线程程序中,线程每次只能做一件事情后面的事情要等待前面的事情完成后才能执行;但是在多线程的程序中则不是这样的,由于多个线程同时都在运行,他们之间往往会产生冲突。比如说在火车站售票系统的代码中有判断当前票数是否大于0的程序段,如果大于零则执行售票操作,但是当两个线程同时访问这段代码时(假如这时只剩下了一张火车票),第一个线程将票售出,与此同时第二个线程已经执行完成判断是否有票的操作,并得出结论票数大于0,于是它也执行售票操作,这样一来所剩的火车票就会出现负数。比如说下面的程序。

源代码:
package MultiTread;
import java.awt.*;
import javax.swing.*;
public class ThreadSafe extends JFrame{
private JPanel jPanel=null;
private JScrollPane jScrollPane;
private static JTextArea jTextArea;
private static Thread thread1,thread2,thread3,thread4;
public ThreadSafe(String title){
super(title);
initUI();
}
private void initUI(){
setContentPane(getJPanel());
setBounds(100,100,350,290);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private JPanel getJPanel(){
if(jPanel==null){
jPanel=new JPanel();
jPanel.setLayout(null);
jTextArea=new JTextArea(100,100);
jScrollPane=new JScrollPane(jTextArea);
jScrollPane.setBounds(0,0,336,250);
jPanel.add(jScrollPane);
}
return jPanel;
}
public static class ThreadSafeTest implements Runnable {
int count= 10;
public void run() {
while (count>0) {
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
jTextArea.append("当前票数是:"+count--+"\n");
}
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
ThreadSafe threadSafe=new ThreadSafe("线程安全");
ThreadSafeTest t= new ThreadSafeTest();
thread1= new Thread(t);
thread2= new Thread(t);
thread3= new Thread(t);
thread4= new Thread(t);
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}

运行的结果:
线程的同步 - 张侦毅 - 张侦毅
 
       当然上面的程序也可以写成下面的这种,其实它们运行的结果都是一样的。不同之处就在于上面的程序是创建了一个ThreadSafeTest内部类,各个线程通过调用共同的内部类来完成售票操作;下面的程序是给每一个线程都分别独立的建立了一个Runnable()方法。

源代码:
package MultiTread;
import java.awt.*;
import javax.swing.*;
public class ThreadSafe extends JFrame{
private JPanel jPanel=null;
private JScrollPane jScrollPane;
private static JTextArea jTextArea;
private static Thread thread1,thread2,thread3,thread4;
    private  int count=10;
public ThreadSafe(String title){
super(title);
initUI();
}
private void initUI(){
setContentPane(getJPanel());
setBounds(100,100,350,290);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private JPanel getJPanel(){
if(jPanel==null){
jPanel=new JPanel();
jPanel.setLayout(null);
jTextArea=new JTextArea(100,100);
jScrollPane=new JScrollPane(jTextArea);
thread1=new Thread(new Runnable(){
public void run(){
while(count>0){
try{
thread1.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
jTextArea.append("目前票数是:"+count--+"\n");
}
}
});
thread2=new Thread(new Runnable(){
public void run(){
while(count>0){
try{
thread2.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
jTextArea.append("目前票数是:"+count--+"\n");
}
}
});
thread3=new Thread(new Runnable(){
public void run(){
while(count>0){
try{
thread3.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
jTextArea.append("目前票数是:"+count--+"\n");
}
}
});
thread4=new Thread(new Runnable(){
public void run(){
while(count>0){
try{
thread4.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
jTextArea.append("目前票数是:"+count--+"\n");
}
}
});
thread1.start();
thread2.start();
thread3.start();
thread4.start();
jScrollPane.setBounds(0,0,336,250);
jPanel.add(jScrollPane);
}
return jPanel;
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
ThreadSafe threadSafe=new ThreadSafe("线程安全");
}
}
运行的结果:
线程的同步 - 张侦毅 - 张侦毅

       很显然,我们绝不会允许在售票时出现负数的操作,此时线程的安全性就不容忽视了,为了解决上面所遇到的问题,我们往往在程序中添加上synchronized关键字,其使用的语法是这样的:

synchronized(Object){
}

       这样一来就可以保证共享的资源不会再次出现负操作了,这就是下面所说的线程的同步机制,示例程序如下所示:

线程的同步机制

源代码:
package MultiTread;
import java.awt.*;
import javax.swing.*;
public class ThreadSafe extends JFrame{
private JPanel jPanel=null;
private JScrollPane jScrollPane;
private static JTextArea jTextArea;
private static Thread thread1,thread2,thread3,thread4;
    private  int count=10;
public ThreadSafe(String title){
super(title);
initUI();
}
private void initUI(){
setContentPane(getJPanel());
setBounds(100,100,350,290);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private JPanel getJPanel(){
if(jPanel==null){
jPanel=new JPanel();
jPanel.setLayout(null);
jTextArea=new JTextArea(100,100);
jScrollPane=new JScrollPane(jTextArea);
thread1=new Thread(new Runnable(){
public void run(){
synchronized(""){
while(count>0){
try{
thread1.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
jTextArea.append("目前票数是:"+count--+"\n");
}
}
}
});
thread2=new Thread(new Runnable(){
public void run(){
synchronized(""){
while(count>0){
try{
thread2.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
jTextArea.append("目前票数是:"+count--+"\n");
}
}
}
});
thread3=new Thread(new Runnable(){
public void run(){
synchronized(""){
while(count>0){
try{
thread3.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
jTextArea.append("目前票数是:"+count--+"\n");
}
}
}
});
thread4=new Thread(new Runnable(){
public void run(){
synchronized(""){
while(count>0){
try{
thread4.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
jTextArea.append("目前票数是:"+count--+"\n");
   }
}
}
});
thread1.start();
thread2.start();
thread3.start();
thread4.start();
jScrollPane.setBounds(0,0,336,250);
jPanel.add(jScrollPane);
}
return jPanel;
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
ThreadSafe threadSafe=new ThreadSafe("线程安全");
}
}

运行的结果:
线程的同步 - 张侦毅 - 张侦毅
 
        由此可以看出,由于共享资源放置在了synchronized定义的区域内,这样当其它程序也获取到这个锁时,必须要等待锁被释放时才能进入该区域。Object 为任意一个对象每个对象都存在一个独立的标志位,这个标志位一共具有两个值,分别是0和1。当一个线程运行到同步块时首先检查的是该标志位,如果标志位的状态为0,表明此同步块中存在其它的线程正在运行当中。这时该线程并不立即执行,而是处于就绪的状态之中,知道同步块中的程序执行完同步块中的代码时为止。这时该对象的标志位被设为1,该线程才能执行同步块中的代码,并将Object的标识位设置为0,这样就可以防止其它的线程执行同步块中的代码。
0 0
原创粉丝点击