线程控制

 

Java的Thread类提供了一组对线程控制的方法,其中常用的有:

 

Thread类的成员静态方法sleep(),使当前正在运行的线程无条件停止运行。必须在方法内指定停止的毫秒值。

 

Thread类的成员函数interrupt方法可以强制唤醒调用对象代表的线程。(无论该线程是以何种方式停止的)

 

Thread类的setDaemon方法可以设置调用对象代表的线程为后台线程,必须要在线程启动前调用。(当程序中只剩余后台线程时,线程自动结束)

 

Thread类的join方法使当前正在运行的线程停止,直到调用对象代表的线程结束。

 

Thread类的yield方法可以使调用对象代表的线程回到等待CPU执行权状态,重新由CPU分发执行权
   


同步下的线程控制:


  线程控制多用于同步线程下,Java也提供了相应的控制功能,对应Lock与synchronized分别有两种组合,使用方式必须在同步区域内,而且调用对象必须与同步对象相关。

 

wait()与notify()以及notifyAll():

 

  因为synchronized的同步对象可以是任意对象,所以以上三个方法被封装在Object内,专门为synchronized区域提供对线程的控制。

 

  wait使当前线程停止,并且会释放持有的同步对象,使其它等待该同步对象的线程可以运行。直到wait方法指定的毫秒值超时,或是被其它线程使用notify方法唤醒,唤醒后接着从wait的下一行向下执行,如果此时该同步区域被其它线程占用,那么被notify后的线程需要在同步区外等待。

 

  一般情况下notify方法唤醒的都是第一个在此同步对象上等待的线程。notifyAll唤醒当前同步对象下的所有线程。

 

  sleep()与wait()有很大的区别。

 

  sleep 属于Thread的静态成员方法。所以在任何地方都可以能过Thread.sleep()调用,使当前线程进入睡眠状态。

 

  wait 是Object的普通成员函数,只能使用在synchronized方法或区域内且必须由synchronized标记的同步对象调用。即被A同步对象wait的线程,必须由A同步对象notify,才能被唤醒。所以这也是wait方法会释放持有同步对象的原因。


  也就是说wait与notify必须放在synchronized的区域或方法内,而且必须由synchronized的区域或方法指定的那个同步对象所调用。否则报IllegalMonitorStateException异常。


  直接不加任何对象调用wait所使用的标记对象锁就是this.wait(),这是很容易忽略的地方。

 

await()与signal()以及signalAll():
 

  对应于Lock,也有同样的三个同步线程控制方法。方法被定义在了interface Condition中。

 

  Lock中有newCondition()方法,可以通过一个Lock或Lock子类的对象调用该方法获取一个在此Lock同步对象上的Condition对象。

 

  然后使用这个Condition对象可以对await与signal以及signalAll方法操作。用法如同wait与notify以及notifyAll在synchronized区域内一样。

 

   Lock与synchronized的区别类似于C++中临界区与互斥对象的区别。synchronized一个同步区对应一个wait和notify。Lock可以对应多个Condition而每个Condition都有自己的await与signal。Lock接口可以对同步代码的操作更广泛,可以一个Lock对象支持多个Condition对象。每newCondition一次都会产生一个新的Condition对象。只要是同一个Lock的newCondition方法得到的Condition对象,都可以在此Lock.lock与Lock.uplock之间使用。

 

  不同Condition对象之间的await与signal操作互不影响。

 

  用更简单的说,notify只能唤醒synchronized同步对象下最先wait的那个线程,或是唤醒synchronized同步对象下全部wait的线程,而Condition对象的signal方法可以唤醒对应的Condition对象await的线程,只要这些Condition对象来自于同一个Lock即可。

 

  其原理也就是在synchronized区域下产生多个有编号的wait与notify组,每个组都被Condition对象封装,互不影响。

 

  synchronized用于规定一个作用域,也可以修饰一个函数。关键词代替C++中的临界区,互斥对象,信号灯,事件对象。happy吗? 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 C# 中,启动线控制控件显示可以通过以下步骤实现: 1. 创建一个线程对象,将需要执行的代码放入线程的方法中。 2. 在线程方法中,使用 Control.Invoke 或 Control.BeginInvoke 方法来更新 UI 控件的显示。 3. 启动线程执行方法。 例如,以下是一个简单的示例代码,通过启动一个线程来更新一个 Label 控件的显示: ``` private void btnStart_Click(object sender, EventArgs e) { // 创建线程对象,指定需要执行的方法 Thread thread = new Thread(new ThreadStart(UpdateLabel)); // 启动线程 thread.Start(); } private void UpdateLabel() { // 使用 Invoke 方法来更新 UI 控件的显示 if (lblStatus.InvokeRequired) { lblStatus.Invoke(new Action(() => lblStatus.Text = "正在更新...")); } else { lblStatus.Text = "正在更新..."; } // 模拟耗时操作 Thread.Sleep(5000); // 使用 Invoke 方法来更新 UI 控件的显示 if (lblStatus.InvokeRequired) { lblStatus.Invoke(new Action(() => lblStatus.Text = "更新完成")); } else { lblStatus.Text = "更新完成"; } } ``` 在这个示例中,我们创建了一个线程对象,并将需要执行的方法 UpdateLabel 指定为线程的方法。在 UpdateLabel 方法中,我们使用 Invoke 或 BeginInvoke 方法来更新 Label 控件的 Text 属性的显示。通过调用线程对象的 Start 方法,启动线程执行方法。 需要注意的是,通过 Invoke 或 BeginInvoke 方法更新 UI 控件的显示时,需要检查当前线程是否是 UI 线程,如果不是则需要使用 Invoke 方法来将更新操作委托到 UI 线程上执行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值