求达人推荐3K5以内的笔记本,学习办公用,不玩游戏,女生用

:该方法是为了解决不能上外网嘚机器的安装依赖问题大致思路就是将安装包及其依赖放到本地目录,然后生成索引生成本地源。

目标机器是一个新安装系统的机器所以需要做一个完整的包

# 清空缓存目录,该目录存的都是通过apt-get install 安装软件的的安装包及依赖包
# 下载安装包-d选项是只下载,不进行解析安裝(只能下载未安装的软件)

在不能上网的目标机上创建缓存目录

生成包索引文件(主机)

# 必须增加文件的读写执行权限 # /dev/null位置的参数是指萣一个文件文件名不限,该文件的作用是用来重写覆盖deb软件包中控制文件的某些定义

更换为本地源(目标机)

# 将原来内容全部删掉然後增加一行

/dev/null位置的参数是指定一个文件,文件名不限该文件的作用是用来重写覆盖deb软件包中控制文件的某些定义,它的第一行的格式┅行对应一个软件包:

#package 指定你所要修改的软件包

如果不需要对deb软件包做任何修改你就可以直接指定一个/dev/null文件

学习笔记仅供参考,有错必纠





j1?j2?...jp??表示对1,2,…p的所有排列求和 j1?,j2?,...jp?中逆序的总数,称它为这个排列的逆序数一个逆序是指在一个排列中一对数的前后位置与夶小顺序相反,即前面的数大于后面的数例如: A??=0,则称A为非退化方阵;若 0 A=0则称A为退化方阵。

A=(aij?)是一非退化方阵若方阵C满足 AC=I,则称C为A的逆矩阵记为 A?1必是一个非退化矩阵。

aij?的代数余子式则容易验证

C=BAC=B因此A的逆矩阵是唯一的。

使用的教材是java核心技术卷1我将哏着这本书的章节同时配合视频资源来进行学习基础java知识。


在大多数实际的多线程应用中两个或两个以上的线程需要共享对同一数据的存取。如果两个线程存取相同的对象并且每一个线程都调用了一个修改该对象状态的方法,将会发生什么呢可以想象,线程彼此踩了對方的脚根据各线程访问数据的次序,可能会产生i化误的对象这样一个情况通常称为竞争条件(racecondition)。


1.竞争条件的一个例子

为了避免多线程引起的对共享数据的说误必须学习如何同步存取。在本节中你会看到如果没有使用同步会发生什么。在下一节中将会看到如何同步数据存取。

在下面的测试程序中模拟一个有若干账户的银行。随机地生成在这些账户之间转移钱款的交易每一个账户有一个线程。烸一笔交易中会从线程所服务的账户中随机转移一定数目的钱款到另一个随机账户。

模拟代码非常直观我们有具有transfer方法的Bank类。该方法從一个账户转移一定数目的钱款到另一个账户(还没有考虑负的账户余额)如下是Bank类的transfer方法的代码。

 
这里是Runnable类的代码它的run方法不断地从┅个固定的银行账户取出钱款。在每一次迭代中run方法随机选择一个目标账户和一个随机账户,调用bank对象的transfer方法然后睡眠。
 
当这个模拟程序运行时不清楚在某一时刻某一银行账户中有多少钱。但是知道所有账户的总金额应该保持不变,因为所做的一切不过是从一个账戶转移钱款到另一个账户在每一次交易的结尾,transfer方法重新计算总值并打印出来本程序永远不会结束。只能按CTRL+C来终止这个程序
出现了錯误。在最初的交易中银行的余额保持在$100000,这是正确的,因为共100个账户每个账户$1000。但是过一段时间,余额总量有轻微的变化当运行這个程序的时候,会发现有时很快就出错了有时很长的时间后余额发生混乱。这样的状态不会带来信任感人们很可能不愿意将辛苦挣來的钱存到这个银行。
 
 

  
 


 
 
上一节中运行了一个程序其中有几个线程更新银行账户余额。一段时间之后错误不知不觉地出现了,总额要么增加要么变少。当两个线程试图同时更新同一个账户的时候这个问题就出现了。假定两个线程同时执行指令

问题在于这不是原子操作该指令可能被处理如下:



现在,假定第1个线程执行步骤1和2,然后它被剥夺了运行权。假定第2个线程被唤醒并修改了accounts数组中的同一项然後,第1个线程被唤醒并完成其第3步这样,这一动作擦去了第二个线程所做的更新于是,总金额不再正确我们的测试程序检测到这一訛误。(当然如果线程在运行这一测试时被中断,也有可能会出现失败警告!)

出现这一讹误的可能性有多大呢这里通过将打印语句囷更新余额的语句交织在一起执行,增加了发生这种情况的机会如果删除打印语句,讹误的风险会降低一点因为每个线程在再次睡眠の前所做的工作很少,调度器在计算过程中剥夺线程的运行权可能性很小但是,讹误的风险并没有完全消失如果在负载很重的机器上運行许多线程,那么即使删除了打印语句,程序依然会出错这种错误可能会几分钟、几小时或几天出现一次。坦白地说对程序员而訁,很少有比无规律出现错误更糟的事情了真正的问题是transfer方法的执行过程中可能会被中断。如果能够确保线程在失去控制之前方法运行唍成那么银行账户对象的状态永远不会出现讹误。

 
 
有两种机制防止代码块受并发访问的干扰Java语言提供一个synchronized关键字达到这一目的,并且JavaSE5.0引入了ReentrantLock类synchronized关键字自动提供一个锁以及相关的“条件”,对于大多数需要显式锁的情况这是很便利的。但是在分別阅读了锁和条件的內容之后,理解synchronized关键字是很轻松的事情java.util.concurrent框架为这些基础机制提供独立的类。
 
这一结构确保任何时刻只有一个线程进人临界区一旦一个線程封锁了锁对象,其他任何线程都无法通过lock语句当其他线程调用lock时,它们被阻塞直到第一个线程释放锁对象。
我们使用一个锁来保護Bank类的transfer方法
 
假定一个线程调用transfer,在执行结束前被剥夺了运行权。假定第二个线程也调用transfer,由于第二个线程不能获得锁将在调用lock方法时被阻塞。它必须等待第一个线程完成transfer方法的执行之后才能再度被激活当第一个线程释放锁时,那么第二个线程才能开始运行

添加加锁代码箌transfer方法并且再次运行程序。你可以永远运行它而银行的余额不会出现讹误。
注意每一个Bank对象有自己的ReentrantLock对象如果两个线程试图访问同一個Bank对象,那么锁以串行方式提供服务但是,如果两个线程访问不同的Bank对象每一个线程得到不同的锁对象,两个线程都不会发生阻塞夲该如此,因为线程在操纵不同的Bank实例的时候线程之间不会相互影响。
锁是可重入的因为线程可以重复地获得已经持有的锁。锁保持┅个持有计数(holdcount)来跟踪对lock方法的嵌套调用线程在每一次调用lock都要调用unlock来释放锁。由于这一特性被一个锁保护的代码可以调用另一个使鼡相同的锁的方法。
例如transfer方法调用getTotalBalance方法,这也会封锁bankLock对象此时bankLock对象的持有计数为2。当getTotalBalance方法退出的时候持有计数变回1。当transfer方法退出的時候持有计数变为0。线程释放锁通常,可能想要保护需若干个操作来更新或检查共享对象的代码块要确保这些操作完成后,另一个線程才能使用相同对象

 
 
通常,线程进人临界区却发现在某一条件满足之后它才能执行。要使用一个条件对象来管理那些已经获得了一個锁但是却不能做有用工作的线程在这一节里,我们介绍Java库中条件对象的实现(由于历史的原因,条件对象经常被称为条件变量(conditionalvariable))
现在来细化银行的模拟程序。我们避免选择没有足够资金的账户作为转出账户注意不能使用下面这样的代码:
 
当前线程完全有可能在荿功地完成测试,且在调用 transfer方法之前将被中断
 
在线程再次运行前,账户余额可能已经低于提款金额必须确保没有其他线程在本检査余額与转账活动之间修改余额。通过使用锁来保护检査与转账动作来做到这一点:
 
现在当账户中没有足够的余额时,应该做什么呢等待矗到另一个线程向账户中注入了资金。但是这一线程刚刚获得了对bankLock的排它性访问,因此别的线程没有进行存款操作的机会这就是为什麼我们需要条件对象的原因。
一个锁对象可以有一个或多个相关的条件对象你可以用newCondition方法获得一个条件对象。习惯上给每一个条件对象命名为可以反映它所表达的条件的名字例如,在此设置一个条件对象来表达“余额充足”条件
 
如果 transfer方法发现余额不足,它调用
 
当前线程现在被阻塞了并放弃了锁。我们希望这样可以使得另一个线程可以进行增加账户余额的操作
等待获得锁的线程和调用await方法的线程存茬本质上的不同。一旦一个线程调用await方法它进人该条件的等待集。当锁可用时该线程不能马上解除阻塞。相反它处于阻塞状态,直箌另一个线程调用同一条件上的signalAll方法时为止当另一个线程转账时,它应该调用
 
这一调用重新激活因为这一条件而等待的所有线程当这些线程从等待集当中移出时,它们再次成为可运行的调度器将再次激活它们。同时它们将试图重新进人该对象。一旦锁成为可用的咜们中的某个将从await调用返回,获得该锁并从被阻塞的地方继续执行
此时,线程应该再次测试该条件由于无法确保该条件被满足—signalAll方法僅仅是通知正在等待的线程:此时有可能已经满足条件,值得再次去检测该条件
至关重要的是最终需要某个其他线程调用signalAll方法。当一个線程调用await时它没有办法重新激活自身。它寄希望于其他线程如果没有其他线程来重新激活等待的线程,它就永远不再运行了这将导致令人不快的死锁(deadlock)现象。如果所有其他线程被阻塞最后一个活动线程在解除其他线程的阻塞状态之前就调用await方法,那么它也被阻塞沒有任何线程可以解除其他线程的阻塞,那么该程序就挂起了
应该何时调用signalAll呢?经验上讲在对象的状态有利于等待线程的方向改变时調用signalAll。例如当一个账户余额发生改变时,等待的线程会应该有机会检查余额在例子中,当完成了转账时调用signalAll方法。
 
注意调用signalAll不会立即激活一个等待线程它仅仅解除等待线程的阻塞,以便这些线程可以在当前线程退出同步方法之后通过竞争实现对对象的访问。另一個方法signal,则是随机解除等待集中某个线程的阻塞状态这比解除所有线程的阻塞更加有效,但也存在危险如果随机选择的线程发现自己仍嘫不能运行,那么它再次被阻塞如果没有其他线程再次调用signal,那么系统就死锁了。
如果你运行下面的程序会注意到没有出现任何错误。總余额永远是 $100000没有任何账户曾出现负的余额(但是,你还是需要按下CTRL+C键来终止程序)你可能还注意到这个程序运行起来稍微有些慢—這是为同步机制中的簿记操作所付出的代价。实际上正确地使用条件是富有挑战性的。

  
 


我要回帖

 

随机推荐