1、多个线程用到同一个资源的话,必须lock
2、为了解决,在竞争的情况下,优先分配资源给A。就是A和B线程都同时在同一时刻需要资源x,然后的话也不清楚系统是具体怎样调度的。或者说怎样调度,都有可能出现上面的问题。解决方法是:在分配资源的时候再增加一个请求,用来排队。以前的请求是,如果这个时候申请然后这个时候也没人在用,就给它。现在的是如果B需要x,先要查看A是否需要。感觉有点像增加代码,然后使得线程判断次数增加,多次调度。所以感觉没有根本解决问题。
也不是说没解决,但是感觉解决了99.9%。hack,对于同一时刻到来的,还是随机化先进性读,或者先进性写了。T__T
怎么说呢,就是读者一来,先申请需要资源,而不是判定是否能拿资源,然后能拿就给它。我们需要的是先申请,然后就相当于锁定了资源x了,后来的写者再需要,需要检查申请队列中是否有读者,有就不行。
3、合法后立马addSignal,不然会出现多个写者同时操作的问题。
4、get, set方法是有用的,对于多线程,还可以维护资源不被多个线程修改,Lock
所以我的感觉是:如果是这样的:
写者先判定while (getNeedReader() > 0) { },判断失败的。
然后读者addReader(1);
然后写者while (getSignal() != 0) { } 也是失败的。
这样的话,结果还是给了写者。
很多人告诉我直接设置线程优先级,但是这样是不对的。因为线程的优先级只是说分配的时间片比较多,不保证上面的情况不能发生。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApp1 { public partial class Form1 : Form { static int signal = 0;//0:empty 1:read 2:write static int numberReader = 0, numberWriter = 0; private static object obj = new object(); private static object si = new object(); private static object reader = new object(); const int dis = 1000; static Stopwatch timer1; static int needReader = 0; class temp { public string[] str; int getSignal() { lock (si) { return signal; } } int getNumber() { if (0 == getSignal()) return 0; else if (1 == getSignal()) return numberReader; else return numberWriter; } void addSignal(int id) { lock (si) { if (id == 1) { signal = 1; numberReader++; } else { signal = 2; numberWriter++; } } } void cutSignal(int id) { lock (si) { if (id == 1) { numberReader--; if (numberReader == 0) signal = 0; } else { numberWriter--; if (numberWriter == 0) signal = 0; } } } void addStringRichText(String str) { lock (obj) { Form1.richTextBox1.Text += str; Form1.richTextBox1.Text += ' '; Form1.richTextBox1.Focus(); Form1.richTextBox1.Select(Form1.richTextBox1.Text.Length, 0); Form1.richTextBox1.ScrollToCaret(); } } void show(String[] str, int id) { Console.Write(id + "+++ "); for (int i = 0; i < str.Length; ++i) { Console.Write(str[i] + " "); } Console.WriteLine(" "); } void addReader(int op) { lock (reader) { needReader += op; } } int getNeedReader() { lock (reader) { return needReader; } } void semWait(int id) { if (id == 1) { addReader(1); // 首先需要申请需要资源,直接资源锁定 if (getSignal() != 2) { addSignal(id); return; } while (getSignal() == 2) { } // 合法后立马addSignal addSignal(1); } else { while (getNeedReader() > 0) { } while (getSignal() != 0) { } //这句后面肯定要是addSignal,立马的 addSignal(2); } } void semSignal(int id) { if (id == 1) { cutSignal(1); addReader(-1); } else { cutSignal(2); } } public void Reader() { addStringRichText("读者:" + str[0] + " 线程创建"); Thread.Sleep(int.Parse(str[2]) * 1000); addStringRichText("读者:" + str[0] + " 在时间:" + (int)timer1.Elapsed.TotalSeconds + " 请求读操作"); /*进行读操作*/ semWait(1); addStringRichText("读者:" + str[0] + " 在时间:" + (int)timer1.Elapsed.TotalSeconds + " 开始读操作"); Thread.Sleep(int.Parse(str[3]) * 1000); addStringRichText("读者:" + str[0] + " 在时间:" + (int)timer1.Elapsed.TotalSeconds + " 结束读操作"); semSignal(1); /*读操作进行完毕*/ } private static object w = new object(); public void Writer() { addStringRichText("写者:" + str[0] + " 线程创建"); Thread.Sleep(int.Parse(str[2]) * 1000); addStringRichText("写者:" + str[0] + " 在时间:" + (int)timer1.Elapsed.TotalSeconds + " 请求写操作"); semWait(2); /*进行读操作*/ addStringRichText("写者:" + str[0] + " 在时间:" + (int)timer1.Elapsed.TotalSeconds + " 开始写操作"); Thread.Sleep(int.Parse(str[3]) * 1000); addStringRichText("写者:" + str[0] + " 在时间:" + (int)timer1.Elapsed.TotalSeconds + " 结束写操作"); semSignal(2); /*读操作进行完毕*/ } } public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { OpenFileDialog op = new OpenFileDialog(); op.ShowDialog(); op.Filter = "All files(*.*)|*.*"; StreamReader reader = null; try { string fileName = op.FileName; if (fileName == "") { return; } richTextBox1.Clear(); reader = new StreamReader(fileName, System.Text.Encoding.Default); string str = reader.ReadLine(); List<Thread> list = new List<Thread>(); while (str != null) { string[] res = str.Split(' '); temp zhu = new temp(); zhu.str = res; if (str.Contains("R") || str.Contains("r")) { Thread rThread = new Thread(zhu.Reader); //rThread.Priority = ThreadPriority.AboveNormal; rThread.Priority = ThreadPriority.AboveNormal; list.Add(rThread); } else if (str.Contains("W") || str.Contains("w")) { Thread wThread = new Thread(zhu.Writer); //wThread.Priority = ThreadPriority.BelowNormal; list.Add(wThread); } else { MessageBox.Show("输入数据有错误!!!【每行数据后面不能有空格】,【文件结束不能有空行】"); return; } //MessageBox.Show(str); str = reader.ReadLine(); } timer1 = new Stopwatch();//计时器类 timer1.Start(); foreach (Thread i in list) { i.Start(); } } catch (Exception error) { MessageBox.Show("错误信息是:" + error.Message, "警告", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { if (reader != null) { reader.Close(); } } const string MutexName = "Multithreading"; var m = new Mutex(false, MutexName); } private void richTextBox1_TextChanged(object sender, EventArgs e) { } private void Form1_Load(object sender, EventArgs e) { System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false; //允许其他线程修改 } } }
所以,我感觉线程不是用于这样的东西的,这样的话结果不确定(或者是我太渣渣了)
线程应该是用在那些,计算方面,new一个线程来辅助计算
这个数据,就会显示是写者优先了,尽管我设置了优先级是读者AboveNormal
对了看到java里写,Main线程的优先级是Noraml的。
2 W 1 5 2 W 1 5 2 W 1 5 2 W 1 5 2 W 1 5 2 W 1 5 2 W 1 5 1 R 1 5
java说,
synchronized可以修饰一个同步一个方法,public synchronized void fun();
同步:就是协同步调,按预定的先后次序进行运行。如:你说完,我再说。
java高级篇P326
一个同步方法在执行之前需要加锁,锁是一种实现资源排他使用的机制。对于实例方法,要给调用该方法的对象加锁。对于静态方法,要给这个类加锁。
但是我不需要对整个类加锁啊,我对静态方法加锁也可以得,???不懂
class myThread implements Runnable { public String s; public void run() { System.out.println(s); } static synchronized void fun() { } }
java的内部类如果需要new一个实体出来,
用name s = new name(); 是不行的。会"is not an enclosing class"
需要Main s = new Main(); 一个实例
然后Main.name bb = s.new name();
有一个问题就是,用lock的话,怎么解决只有一个return的语句呢???
因为lock.lock()之后,还需要lock.unlock()
import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Main { static bank bk = new bank(); public static void main(String[] args) { ExecutorService ex = Executors.newCachedThreadPool(); ex.execute(new cutMoney()); ex.execute(new addMoney()); ex.shutdown(); } static class addMoney implements Runnable { @Override public void run() { while (true) { int val = (int)(Math.random() * 10) + 1; bk.add(val); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } static class cutMoney implements Runnable { @Override public void run() { while (true) { int val = (int)(Math.random() * 10) + 1; try { while (!bk.cut(val)) {} } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } static class bank { private Lock lock = new ReentrantLock(); private Condition signal = lock.newCondition(); private int money = 0; bank() {} // synchronized int getMoney() { // 只能这样嘛?用lock感觉不行啊 // return money; // } int getMoney() { // 只能这样嘛?用lock感觉不行啊 lock.lock(); try { return money; } finally { lock.unlock(); } } String getNowTime() { SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ");//设置日期格式 return (df.format(new Date()));// new Date()为获取当前系统时间 } boolean cut(int val) throws InterruptedException { lock.lock(); try { while (money < val) { System.out.println(getNowTime() + " 不够 " + val + " " + " 现在有 " + money); signal.await(); //等待,不需要一直判判判 } money -= val; System.out.println(getNowTime() + " 扣除" + val + "钱"); } catch (InterruptedException e) { } finally { lock.unlock(); } return true; } void add(int val) { lock.lock(); try { money += val; System.out.println(getNowTime() + " 转入" + val + "钱"); signal.signalAll(); // 唤醒 } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } } }
我的方法是:
1、用synchronized
2、try的finally语句是必须进行的