text:
If you're trying to reduce the sugar and calories in your diet, you may be turning to artificial sweeteners or other sugar substitutes. You aren't alone.
Today artificial sweeteners and other sugar substitutes are found in a variety of food and beverages marketed as "sugar-free" or "diet," including soft drinks, chewing gum, jellies, baked goods, candy, fruit juice, and ice cream and yogurt.
Just what are all these sweeteners? And what's their role in your diet?
Understanding artificial sweeteners and other sugar substitutes
Sugar substitutes are loosely considered any sweetener that you use instead of regular table sugar (sucrose). Artificial sweeteners are just one type of sugar substitute. The chart lists some popular sugar substitutes and how they're commonly categorized.
|Artificial sweeteners
|Sugar alcohols
|Novel sweeteners
|Natural sweeteners
|Acesulfame potassium (Sunett, Sweet One)
|Stevia extracts (Pure Via, Truvia)
|Agave nectar
|Aspartame (Equal, NutraSweet)
|Hydrogenated starch hydrolysate
|Tagatose (Naturlose)
|Date sugar
|Fruit juice concentrate
|Saccharin (SugarTwin, Sweet'N Low)
|Sucralose (Splenda)
|Maple syrup
The topic of sugar substitutes can be confusing. One problem is that the terminology is often open to interpretation. For instance, some manufacturers call their sweeteners "natural" even though they're processed or refined, as is the case with stevia preparations. And some artificial sweeteners are derived from naturally occurring substances — sucralose comes from sugar, for example.
Regardless of how they're classified, sugar substitutes aren't magic bullets for weight loss. Take a closer look.
Artificial sweeteners
Artificial sweeteners are synthetic sugar substitutes but may be derived from naturally occurring substances, including herbs or sugar itself. Artificial sweeteners are also known as intense sweeteners because they are many times sweeter than regular sugar.
Uses for artificial sweeteners
Artificial sweeteners are attractive alternatives to sugar because they add virtually no calories to your diet. In addition, you need only a fraction compared with the amount of sugar you would normally use for sweetness.
Artificial sweeteners are widely used in processed foods, including baked goods, soft drinks, powdered drink mixes, candy, puddings, canned foods, jams and jellies, dairy products, and scores of other foods and beverages.
Artificial sweeteners are also popular for home use. Some can even be used in baking or cooking. Certain recipes may need modification, though, because artificial sweeteners provide no bulk or volume, as does sugar. Check the labels on artificial sweeteners for appropriate home use.
Some artificial sweeteners may leave an aftertaste. You may need to experiment with artificial sweeteners to find one or a combination that you enjoy most.
Possible health benefits of artificial sweeteners
One benefit of artificial sweeteners is that they don't contribute to tooth decay and cavities. They may also help with the following:
- Weight control. One of the most appealing aspects of artificial sweeteners is that they are non-nutritive — they have virtually no calories. In contrast, each gram of regular table sugar contains 4 calories. A teaspoon of sugar is about 4 grams. For perspective, consider that one 12-ounce can of a sweetened cola contains 8 teaspoons of added sugar, or about 130 calories. If you're trying to lose weight or prevent weight gain, products sweetened with artificial sweeteners rather than with higher calorie table sugar may be an attractive option. On the other hand, some research has suggested that consuming artificial sweeteners may be associated with increased weight, but the cause is not yet known.
- Diabetes. Artificial sweeteners may be a good alternative to sugar if you have diabetes. Unlike sugar, artificial sweeteners generally don't raise blood sugar levels because they are not carbohydrates. But because of concerns about how sugar substitutes are labeled and categorized, always check with your doctor or dietitian about using any sugar substitutes if you have diabetes.
Possible health concerns with artificial sweeteners
Artificial sweeteners have been the subject of intense scrutiny for decades. Critics of artificial sweeteners say that they cause a variety of health problems, including cancer. That's largely because of studies dating to the 1970s that linked saccharin to bladder cancer in laboratory rats. Because of those studies, saccharin once carried a warning label that it may be hazardous to your health.
But according to the National Cancer Institute and other health agencies, there's no sound scientific evidence that any of the artificial sweeteners approved for use in the U.S. cause cancer or other serious health problems. And numerous research studies confirm that artificial sweeteners are generally safe in limited quantities, even for pregnant women. As a result of the newer studies, the warning label for saccharin was dropped.
Artificial sweeteners are regulated by the Food and Drug Administration (FDA) as food additives. They must be reviewed and approved by the FDA before being made available for sale. In some cases, the FDA declares a substance "generally recognized as safe" (GRAS). These GRAS substances, including highly refined stevia preparations, are deemed by qualified professionals based on scientific data as being safe for their intended use, or they have such a lengthy history of common use in food that they're considered generally safe and don't require FDA approval before sale.
The FDA has also established an acceptable daily intake (ADI) for each artificial sweetener. This is the maximum amount considered safe to consume each day over the course of your lifetime. ADIs are intended to be about 100 times less than the smallest amount that might cause health concerns.


text:
You won't be able to dismiss this by usual means (escape or click button), but you can close it programatically based on user choices or actions.
"I am so happy with my invitations. The quality of the paper is great...weighty and perfectly textured. The design is so elegant. The only thing I would say is that they are smaller than I expected but I was reading that's that is a good thing as it saves on postage! Service was also prompt and a pleasant experience."
"Great design with a tint of nostalgia. WPD designers are easy to work with - incorporated more wording on the back of the card at my request. Customer service was also top notch. My cards were delayed - WPD happily sent me another batch for next day delivery. Would definitely recommend this design and WPD in general to friends."
"Our invitations arrived recently (sooner than expected) and look absolutely beautiful! The design requests we submitted were perfect and really helped to make our invitations unique."
"I ordered these for my wedding invitations, and they came our gorgeous! I loved the design and the color options they offered. I went with the square option, and used the cream colored background and solid color for the back design. I love that the paper is already shimmery, which also adds to the design. I did think the paper was a little thin, and maybe I should have ordered a thicker paper, but overall all I was very happy with my order and my invitations! My order also arrived earlier than expected."
"I am so happy with these invitations! They are simple, yet beautiful and classy. I wanted to put all the information (reception and all) on one card, and I needed to make a second set in another language. The designer followed my instructions perfectly and made great suggestions to fit the text on the page. They turned out even better than expected. The paper quality (I used the shimmer paper) was excellent. I would recommend the shimmer paper. I can't say enough about the service as well. The proofs were done so quickly, the people on the phone were amazing and friendly and the package was delivered days ahead of time. The only hiccup I had was that they were unable to tell me what the customs/duties would be so I had to just keep my fingers crossed. In the end, it wasn't so expensive (about $60 for Canada). I would recommend Wedding Paper Divas to any bride-to-be!"

subset: commoncrawl


text:
United Microelectronics Corp. this week disclosed its plans to start investing into promising startups with the help of its newly created investment subsidiary. The first investments set to be made by UMC New Business Investment Corp. will be into LED and solar power technologies. The subsidiary will operate New Business Development Center.
UMC established the center to capitalize in high growth and high profit potential industries through timely strategic investment. This will bring new momentum for UMC to further grow and enhance UMC's future asset turnover and profitability, according to the company. Capital for UMC's 100% owned subsidiary is expected to reach NTD 1.5 billion (about $45 million). The company will invest based on the research and evaluation performed by UMC New Business Development Center.
Recently, major developed and developing countries have listed energy saving and carbon reduction as primary administrative policies to face the challenge of potential energy shortages in the future. Technologies for renewable energy and energy saving will become the focus for future technology development; the growth of related industries is predictable. The utilization of solar energy has high development potential in the renewable energy sector, while LED is a focus area for energy saving. UMC's knowledge and technologies are highly applicable to the fundamentals of these two industries; hence UMC New Business Development Center will focus on these two areas by utilizing UMC's existing expertise and technologies.
In the short-to-mid term, UMC plans to complete the development of related technologies and establish a preliminary scale of operations. For the long term, as key proficiencies mature and resource integration is complete, the new energy business is expected to become another UMC core business with high competitive advantages.
In the future, the company will acquire absolute majority of the investees' shares and aggressively participate in the decision-making process and operation of the invested companies.
Tags: UMC, Semiconductor, Business


text:
Senate Finance Committee chairman Max Baucus, D-Mont., and Sen. Jon Tester, D-Mont., have introduced legislation that would expand an existing tax credit for hiring veterans to encourage further hiring while making it easier for business claim.
Senate Bill Would Expand Tax Credit for Hiring Veterans
Washington, D.C. (January 25, 2013)
Get access to this article and thousands more...
All Accounting Today articles are archived after 7 days. REGISTER NOW for unlimited access to all recently archived articles, as well as thousands of searchable stories. Registered Members also gain access to exclusive industry white paper downloads, web seminars, podcasts, blog discussions, and conference discounts. Registered members may also choose to receive our exclusive Tax Pro Today e-newsletters covering the latest breaking news, opinions from industry leaders and developing trends.


text:
Two car crash results in minor injury
July 20, 2011 —
Honesdale Police investigated a two car crash in the 800 block of Main St, Monday, July 18.
Faith Collins, 18, of Beach Lake, PA was driving southbound on Main St. in the left lane, when she proceeded to turn into the right lane; her vehicle struck the front driver side of an 2012 Jeep SUV, owned by Arnold Crum, 85, of Milanville, PA.
Honesdale EMS assisted at the scene. Megan Robertson, 19, of Honesdale, PA, was a passenger of Collins'. She reported a minor head injury, but declined medical attention. Robertson was not wearing a seatbelt.
Crum was going south in the right lane after having just exiting a parking space on the right side of Main St.
Crum's vehicle hit a parked vehicle on the right side of the road as a result of being struck by Collins. The parked vehicle that was struck left the scene of the crash.
If anyone may have witnessed the crash or know the identity of the owner of the parked car that was struck to contact Police at 570-253-1900.
Detective LeStrange investigated the crash.


text:
Legal Resources for Disaster Victims
Both State and Federal governments have the statutory and regulatory authority to make arrangements for the provision of legal services to victims of disaster. Thus, upon declaration, either by the Governor alone, or by the Governor and the President, Colorado lawyers may be called upon to provide free emergency legal services.
Three possible times in which the CBA Disaster Legal Assistance program may be initiated are:
At this time our Flood Legal Relief Helpline is closed. If you would like more information on flood legal relief colofloodlegalrelief.org.


text:
View Rule
|View EO 12866 Meetings
|Printer-Friendly Version Download RIN Data in XML
|Publication ID: Spring 2011
|Title: Water Quality Management and Best Management Practices for Water and Soil Conservation
|Abstract: A new servicewide handbook, Best Management Practices for Water and Soil Conservation, is proposed to provide consistent national guidance for implementing the Agency's nonpoint source pollution control program in accordance with the Federal Water Pollution Control Act (commonly referred to as Clean Water Act; 33 U.S.C. 1251 et seq.), Safe Drinking Water Act (42 U.S.C. 311f et seq.), Department regulation (9500-007), and Agency policy (FSM 2532). Minor revisions to Agency policy to acknowledge and institutionalize the new handbook are also expected. This program is not new for the Forest Service; however, the guidance is. Existing regional BMPs, soil and water conservation practices, and monitoring programs that have proven to be successful are the foundation of the policy. Common aspects of these programs are being combined to standardize and streamline current Forest Service nonpoint source water pollution prevention programs for improved efficiency, consistency, and reporting. The Forest Service National BMP Program has two parts: * A set of BMPs that will encompass water resource protection measures for a full range of National Forest System land management activities. * A monitoring program to determine if practices are implemented and effective at meeting water resource and beneficial use protection objectives. Consolidating the many existing field-issued handbooks into a new servicewide directive is prompting both extensive internal review and a broad external review with interested publics. These reviews are critical to the success of implementing a consistent, national program. The proposed directive is expected to provide more effective implementation of the Clean Water Act, Safe Drinking Water Act, the 1982 and 2008 NFMA planning regulations, and Department and Agency policies for protecting water resources from point sources of pollution.
|Agency: Department of Agriculture(USDA)
|Priority: Other Significant
|RIN Status: Previously published in the Unified Agenda
|Agenda Stage of Rulemaking: Proposed Rule Stage
|Major: Undetermined
|Unfunded Mandates: No
|CFR Citation: None (To search for a specific CFR, visit the Code of Federal Regulations.)
|Legal Authority: Not Yet Determined
Legal Deadline:
|Regulatory Flexibility Analysis Required: Undetermined
|Government Levels Affected: None
|Federalism: No
|Included in the Regulatory Plan: No
|RIN Data Printed in the FR: No
Agency Contact:
Lorrie Parker
Regulatory Analyst
Department of Agriculture
Forest Service
ATTN: ORMS, D&R Branch, 1400 Independence Avenue SW,
Washington, DC 20250-0003
Phone:202 205-6560
Fax:202 260-6539
Email: email@example.com


text:
Bad Luck Or Bad Baseball?
Is it bad luck or bad baseball? It looked like luck may have been in the Phillies favor when Red Sox starter Daisuke Matsuzaka was sent to the DL minutes before the game started today. Dice-K beat up the Phillies in their last meeting, so this must be good news. Scott Atchison, a career minor leaguer who also played in Japan, made his first career major league start in place of Dice-K. Again, this seemed like good news, right?
Wrong. Because absolutely nothing has gone well for the Phillies lately, and this game would be no different. Joe Blanton has been as bad as he could be since coming off the DL in early May. By the 2nd inning of this game, Blanton had given up 34 runs, 11 homers and 11 walks in 45 innings pitched this year.
And the damage did not end there…Blanton allowed 9 runs total, matching Jamie Moyer yesterday, on 13 hits and a walk by the time he was done, after 4 pathetic innings. His ERA is now 7.28.
Blanton loaded the bases in the 2nd inning, right after the offense scored two runs for him. He then threw ONE pitch to rookie, Daniel Nava, who in his first major league at-bat, hit a grand slam! Unbelievable. It looked like the Phillies had morphed into a black cat with a #13 tattoo, under a black cloud standing on top of a broken mirror, sprinkled with spilled salt. But was that bad luck or just Joe Blah-anton?
Blanton needs to go. Obviously, no one will want him with his gigantic 7.28 ERA and gigantic salary, so what are the options? Put him back on the DL or send him to the minors. Brett Myers did this voluntarily back in 2008 and came back to help them win the World Series. The Phillies can bring back Nelson Figueroa or someone else from the minors. I would rather see a rookie get raked for 9 runs than a veteran who is not living up to his end of the deal. How about Nate Bump? He has some experience and was recently clocked at 103mph. Go get him!
The Phillies have made a lot of mistakes this year and last, many of which have been overshadowed by the acquisition of Roy Halladay. Letting Myers go was clearly an error in judgment. I said it before, but because most people have a personal dislike of Myers, most were happy to see him go. For the Astros this year, Myers has not allowed more than 4 runs in any game, has not pitched fewer than 6 innings in any game and his ERA is a very respectable 3.18.
And do not even get me started on Cliff Lee. Because the Mariners are not doing well, Lee will likely be traded before the deadline and it looks like he may wind up in the NL East. Imagine this: Lee goes to Mets or the Braves who make the playoffs, leaving the Phillies in the dust. You want to throw up right now, don't you?
And remember signing a 36 year-old Raul Ibanez, now 38, to a 3-year contract? It looked like a good idea for ½ a year in 2009; now, not so much. Raul, we still love ya, but things are not going well. Ibanez is hitting .247 and is getting slower in the outfield.
The Phillies also extended Blanton's contract this off-season, giving him 3 more years and $24 million dollars. They noted his "consistency," which I have never agreed with, and his ability to pitch many innings as reasons for the extension. Well, all those innings have taken their toll as evidenced by Blanton's current ERA plus the pre-season injury and DL stint.
By the way, the Phillies offense died after Blanton dug a huge hole for them. The managed only 7 hits and 3 of those came from back-up catcher Brian Schneider. The Phillies went on to lose the game by a score of 2-10.
I could go on, but I think that is enough for one day. The Phillies have now slid from 1st place to 3rd place in the NL East and if the Marlins keep winning, they will be in 4th place shortly. I mentioned holding off on hitting the panic button last week; well, it is now time. Let the panic begin. This past month may be a foretelling of the horror to come.
Photoshopping by Jenn
*Read more about the Phillies at my other home page, Phightin' Phils Phorum in the My Team Rivals network*
7 Comments
I agree with you on most of your points. You were able to say much that my blog entry couldn't. I just couldn't find the words today.The team, however, keeps saying that it isn't time to hit the panic button. They even had a team meeting before yesterdays's game. I think that they're trying to stay positive which isn't a bad thing. When the game started, they looked determined. Things were in their favor with the last minute change of pitchers. Blanton was reported to have worked on his pitching. All was for naught though. They just keep on getting beaten up and , sad to say, they're allowing it to happen. I'm hangin in there because that's what true fans do. It's not easy though.
I'm not as sure that the Mariners will look to trade Lee. They're disappointing, yes, but they also think they can win, and I don't see them abandoning ship so early into the process.
The thing that kills me about this team is the bench. They're historically weak against AL teams, and I think part of the reason is that they have no DH when they go to AL ballparks. Dobbs (.138) and Gload (.213) aren't much better than sending a pitcher up to hit. In fact, Hamels is hitting .167. Maybe he should DH today?🙂
Of course, the peril of sliding to 4th place is having 3 teams to jump over to get to first. It's a bad way to start the second half, and with games against the Yankees and Twins looming, the future is kind of bleak.
I understand your impulse to throw up, Jenn! You guys have had a bad streak and yesterday must have been a total bummer – especially because you thought you had luck on your side going into the game. Maybe the Phillies can get Lee back?
How quickly Phillies fans seem to forget. Blanton has been horrible the first half of the season for years. For whatever reason he doesn't find his stride until July. He was something like 5-12 when the Phils traded for him at Oakland. Last year he was amazingly hittable the first half of the season. So give up on him and trade him as quickly as you can and we Braves fans will be happy to see him gone when he hits his stride for someone else down the stretch.
This has been the most depressing 3-4 weeks watching these games. What has happened? Where are my boys? It is so painful because we rightfully expect more and they are not playing up to their potential. It is an embarrassment that we fans do not deserve to witness. Does anyone have the number to the suicide prevention hotline? I may need it handy if this continues. LOL
Hmmm… perhaps this is the ghost of Mets teams past haunting the Phils into becoming terrible overnight.
Barb – we are all trying to hang too…it is going to be a rough summer.
Muleman- I know, the bench is just one more thing that is killing us. I like the idea of Hamels as the DH…lol
Jane – this may all be good news for the Yanks, but I hope they at least put up a fight, ya know? And I think most would give their non-pitching arm to have Lee back ;o)
Leec – Blanton is a slow starter, but has never been THIS bad. I could deal with slow, but his season has been a total disaster. He needs to go down and work out his issues or go home. I think the early season injury is affecting him.
Redhead – If you find a #, please pass it on! LOL
Jeff – METS is a 4-letter word. ;o)


text:
view full screen
Reversible Printed Metallic Snake/Patent Belt
Style: 570092724
Out of Stock
Shadowy gray stripes make this silver snake a rare exotic. And on the flip side, glossy black patent shine makes it irresisitbly versatile. Silvertone buckle glitters with pavé crystals.
- Sized to wear at the waist. To wear at the hip, you may need to order one size up.
- 1.5" wide.
- Manmade and genuine leather. Imported.
- Coordinate with the Printed Metallic Snake Heel and Clutch.
Read more… Read less…


text:
Editor's note: Last week, in part one of this two-part excerpt from Java Threads, 3rd Edition, authors Scott Oaks and Henry Wong looked at the new
java.util.concurrent package. This week, the authors conclude by looking at deadlock and how to deal with it.
Deadlock between threads competing for the same set of locks is the hardest problem to solve in any threaded program. It's a hard enough problem, in fact, that it cannot be solved in the general case. Instead, we try to offer a good understanding of deadlock and some guidelines on how to prevent it. Preventing deadlock is completely the responsibility of the developer—the Java virtual machine does not do deadlock prevention or deadlock detection on your behalf.
Related Reading
Java Threads
Let's revisit the simple deadlock example from Chapter 3.
package javathreads.examples.ch03.example8;
public class ScoreLabel extends JLabel implements CharacterListener {
private Lock adminLock = new ReentrantLock( );
private Lock charLock = new ReentrantLock( );
private Lock scoreLock = new ReentrantLock( );
public void resetScore( ) {
try {
charLock.lock( );
scoreLock.lock( );
score = 0;
char2type = -1;
setScore( );
} finally {
charLock.unlock( );
scoreLock.unlock( );
public void newCharacter(CharacterEvent ce) {
try {
scoreLock.lock( );
charLock.lock( );
// Previous character not typed correctly: 1-point penalty
if (ce.source == generator) {
if (char2type != -1) {
setScore( );
char2type = ce.character;
// If character is extraneous: 1-point penalty
// If character does not match: 1-point penalty
else {
if (char2type != ce.character) {
} else {
char2type = -1;
setScore( );
} finally {
scoreLock.unlock( );
charLock.unlock( );
To review, deadlock occurs if two threads execute the
newCharacter() and
resetScore() methods in a fashion that each can grab only one lock. If
newCharacter() method grabs the score lock
while the
resetScore() method grabs the character
lock, they both eventually wait for each other to release the locks.
The locks, of course, are not released until they can finish
execution of the methods. And neither thread can continue because
each is waiting for the other thread's lock. This
deadlock condition cannot be resolved automatically.
Virtual Machine-Level Deadlock Detection
In certain cases, the virtual machine can detect that two threads are deadlocked. It's possible to obtain a stack trace for all active threads in the virtual machine through a platform-specific operation. On Solaris, Linux, and other Unix systems, sending the virtual machine a -3 signal (via the kill command) produces that output. On Windows systems, entering Ctrl-Break produces the stack output.
If two or more threads are waiting for each other's locks, the virtual machine detects this and prints out that information in the thread dump. However, even though the virtual machine has detected the deadlock, it does not take any steps to resolve it.
The virtual machine cannot detect other kinds of deadlock, such as
the first case we examined in Chapter 3. In
that example, the deadlock occurred because the
As we mentioned at the time, this example is simple, but more complicated conditions of deadlock follow the same principles outlined here: they're harder to detect, but nothing more is involved than two or more threads attempting to acquire each other's locks (or, more correctly, waiting for conflicting conditions).
Deadlock is difficult to detect because it can involve many classes that
call each other's synchronized sections (that is,
synchronized methods or synchronized blocks) in an order that
isn't apparently obvious. Suppose we have 26
classes, A to Z, and that the synchronized methods of class A call
those of class B, those of class B call those of class C, and so on,
until those of class Z call those of class A. If two threads call any
of these classes, this could lead us into the same sort of deadlock
situation that we had between the
resetScore() methods, but
it's unlikely that a programmer examining the source
code would detect that deadlock.
Nonetheless, a close examination of the source code is the only option presently available to determine whether deadlock is a possibility. Java virtual machines do not detect deadlock at runtime, and while it is possible to develop tools that examine source code to detect potential deadlock situations, no such tools exist yet for Java.
The simplest way to avoid deadlock is to follow this rule. When a lock is held, never call any methods that need other locks—i.e., never call a synchronized method of another class from a synchronized method. This is a good rule that is often advocated, but it's not the ideal rule for two reasons:
It's impractical: many useful Java methods are synchronized, and you'll want to call them from your synchronized method. As an example, many of the collection classes discussed in Chapter 8 have synchronized methods. To avoid the usage of collection classes from synchronized methods would prevent data from being moved or results from being saved.
It's overkill: if the synchronized method you're going to call does not in turn call another synchronized method, there's no way that deadlock can occur. Furthermore, if the class or library is accessed only through its class interface—with no cross-calling—placing extra restrictions on using the library is silly.
Nonetheless, if you can manage to obey this rule, there will be no deadlocks in your program.
Another frequently used technique to avoid deadlock is to lock some higher-order object that is related to the many lower-order objects we need to use. In our example, that means removing the efficiency that causes this deadlock: to use only one lock to protect the score and the character assignments.
Of course, this is only a simple example: we don't need to lock everything. If we can isolate the location of the deadlock, we can use a slightly higher order lock only to protect the methods that are having problems. Or we can make a rule that adds the requirement that an additional lock be held prior to acquiring the problem locks. All these variations of locking multiple objects suffer from the same lock granularity problem that we're about to discuss.
The problem with this technique is that it often leads to situations where the lock granularity is not ideal. By synchronizing with only one lock, we are preventing access to variables we may not be changing or even using. The purpose of threaded programming is to accomplish tasks simultaneously—not to have these threads waiting on some global lock. Furthermore, if we've done our program design correctly, there was probably a reason why we attempted to acquire multiple locks rather than a single global lock. Solving deadlock issues by violating this design becomes somewhat counterproductive.
The most practical rule to avoid deadlock is to make sure that the locks are always acquired in the same order. In our example, it means that either the score or character lock must be acquired first—it doesn't matter which as long as we are consistent. This implies the need for a lock hierarchy—meaning that locks are not only protecting their individual items but are also keeping an order to the items. The score lock protects not only the values of the score, but the character lock as well. This is the technique that we used to fix the deadlock in Chapter 3:
package javathreads.examples.ch03.example9;
public class ScoreLabel extends JLabel implements CharacterListener {
public void resetScore( ) {
try {
scoreLock.lock( );
charLock.lock( );
score = 0;
char2type = -1;
setScore( );
} finally {
charLock.unlock( );
scoreLock.unlock( );
Since the
resetScore() method now also grabs the
score lock first, it is not possible for any thread to be waiting for
the score lock while holding the character lock. This means that the
character lock may eventually be grabbed and released, followed by
the eventual release of the score lock. A deadlock does not occur.
Again, this is a very simple example. For much more complex situations, we may have to do all of the following:
Use only locking objects—things that implement the
Lock interface—and avoid use of the
keyword. This allows the separation of the locks from the objects in
the application. We do this even with our simple example.
Understand which locks are assigned to which subsystems and understand the relationships between the subsystems. We define a subsystem as a class, group of classes, or library that performs a relatively independent service. The subsystem must have a documented interface that we can test or debug in our search for deadlocks. This allows us to form groups of locks and map out potential deadlocks.
Form a locking hierarchy within each subsystem. Unlike the other two steps, this can actually hurt the efficiency of the application. The subsystem needs to be studied. The relationship of the locks must be understood in order to be able to form a hierarchy that will have minimal impact on the efficiency of the application.
If you are developing a very complex Java program, it's a good idea to develop a lock hierarchy when the application is being designed. It may be very difficult to enforce a lock hierarchy after much of the program has been developed. Finally, since there is no mechanism to enforce a lock hierarchy, it is up to your good programming practices to make sure that the lock hierarchy is followed. Following a lock acquisition hierarchy is the best way to guarantee that deadlock does not occur in your Java program due to synchronization.
There are a few more concerns about deadlock when using the
Lock interface (or any locking mechanism that is not the Java
synchronized keyword). The first is illustrated by
how we have used the
Lock class in every example
up to this point. Our
resetScore() method can be
easier written (and understood) as follows:
public void resetScore( ) {
scoreLock.lock( );
charLock.lock( );
score = 0;
char2type = -1;
setScore( );
charLock.unlock( );
scoreLock.unlock( );
However, what happens if the thread that calls the
resetScore() method encounters a runtime
exception and terminates? Under many threading systems, this leads to
a type of deadlock because the thread that terminates does not
automatically release the locks it held. Under those systems, another
thread could wait forever when it tries to change the score. In Java,
however, locks associated with the
keyword are always released when the thread leaves the scope of the
synchronized block, even if it leaves that scope due to an exception.
So in Java when using the
synchronized keyword, this type of deadlock never
But we are using the
Lock interface instead of the
synchronized keyword. It is not possible for Java
to figure out the scope of the explicit lock—the
developer's intent may be to hold the lock even on
an exception condition. Consequently, in this new version of the
resetScore() method, if the
setScore() method throws a runtime exception, the lock is never
freed since the
unlock() methods are never
There is a simple way around this: we can use Java's
finally clause to make sure that the locks are
freed upon completion, regardless of how the method exits. This is
what we've done in all our examples.
By the way, this antideadlock behavior of the
synchronized keyword is not necessarily a good
thing. When a thread encounters a runtime exception while it is
holding a lock, there's the
possibility—indeed, the expectation—that it will leave
the data it was manipulating in an inconsistent state. If another
thread is then able to acquire the lock, it may encounter this
inconsistent data and proceed erroneously.
When using explicit locks, you should not only use the
finally clause to free the lock, but you should
also test for, and clean up after, the runtime exception condition.
Unfortunately, given Java's semantics, this problem
is impossible to solve completely when using the
synchronized keyword or by using the
finally clause. In fact, it's
exactly this problem that led to the deprecation of the
stop() method: the
method works by throwing an exception, which has the potential to
leave key resources in the Java virtual machine in an inconsistent
Since we cannot solve this problem completely, it may sometimes be better to use explicit locks and risk deadlock if a thread exits unexpectedly. It may be better to have a deadlocked system than to have a corrupted system.
Since the
Lock interface
provides options for when a lock can't be grabbed; can we use
those options to prevent deadlock? Absolutely. Another way to prevent
deadlock is not to wait for the lock—or at least, to place
restrictions on the waiting period. By using the
tryLock() method to provide alternatives in the
algorithm, the chances of deadlock can be greatly mitigated. For
example, if we need a resource but have an alternate (maybe slower)
resource available, using the alternate resource allows us to
complete the operation and ultimately free any other locks we may be
holding. Alternatively, if we are unable to obtain the lock within a
time limit, perhaps we can clean up our state—including
releasing the locks we are currently holding—and allow other
conflicting threads to finish up and free their locks.
Unfortunately, using explicit locks in this fashion is more complex than using a lock hierarchy. To develop a lock hierarchy, we simply have to figure out the order in which the locks must be obtained. To use timeouts, we need to design the application to allow alternative paths to completion, or the capability to "undo" operations for a later "redo." The advantage to timeouts is that there can be a greater degree of parallelism. We are actually designing multiple pathways to completion to avoid deadlock instead of placing restrictions on the algorithm in order to avoid deadlock.
You must decide whether these types of benefits outweigh the added complexity of the code when you design your Java program. If you start by creating a lock hierarchy, you'll have simpler code at the possible expense of the loss of some parallelism. We think it is easier to write the simpler code first and then address the parallelism problems if they become a performance bottleneck.
The problem with deadlock is that it causes the program to hang indefinitely. Obviously, if a program hangs, deadlock may be the cause. But is deadlock always the cause? In programs that wait for users, wait for external systems, or have complex interactions, it can be very difficult to tell a deadlock situation from the normal operation of the program. Furthermore, what if the deadlock is localized? A small group of threads in the program may deadlock with each other while other threads continue running, masking the deadlock from the user (or the program itself). While it is very difficult to prevent deadlock, can we at least detect it? To understand how to detect deadlock, we must first understand its cause.
Figure 6-1 shows two cases of threads and locks waiting for each other. The first case is of locks waiting for the owner thread to free them. The locks are owned by the thread so they can't be used by any other thread. Any thread that tries to obtain these locks is placed into a wait state. This also means that if the thread deadlocks, it can make many locks unavailable to other threads.
Figure 6-1. Lock trees
The second case is of threads waiting to obtain a lock. If the lock is owned by another thread, the thread must wait for it to be free. Technically, the lock does not own the thread, but the effect is the same—the thread can't accomplish any other task until the lock is freed. Furthermore, a lock can have many threads waiting for it to be free. This means that if a lock deadlocks, it can block many waiting threads.
We have introduced many new terms here—we'll explain them before we move on. We define a deadlocked lock as a lock that is owned by a thread that has deadlocked. We define a deadlocked thread as a thread that is waiting for a deadlocked lock. These two definitions are admittedly circular, but that is how deadlocks are caused. A thread owns a lock that has waiting threads that own a lock that has waiting threads that own a lock, and so on. A deadlock occurs if the original thread needs to wait for any of these locks. In effect, a loop has been created. We have locks waiting for threads to free them, and threads waiting for locks to be freed. Neither can happen because indirectly they are waiting for each other.
We define a hard wait as a thread trying to acquire a lock by waiting
indefinitely. We call it a soft wait if a timeout is assigned to the
lock acquisition. The timeout is the exit strategy if a deadlock
occurs. Therefore, for deadlock detection situations, we need only be
concerned with hard waits. Interrupted waits are interesting in this
regard. If the wait can be interrupted, is it a hard wait or a soft
wait? The answer is not simple because there is no way to tell if the
thread that is implemented to call the
interrupt() method at a later time is also involved in the deadlock.
For now, we will simply not allow the wait for the lock to be
interrupted. We will revisit the issue of the delineation between
soft and hard waits later in this chapter. However, in our opinion,
interruptible waits should be considered hard waits since using
interrupts is not common in most programs.
Assuming that we can keep track of all of the locks that are owned by a thread and keep track of all the threads that are performing a hard wait on a lock, is detecting a potential deadlock possible? Yes. Figure 6-2 shows a potential tree that is formed by locks that are owned and formed by hard waiting threads. Given a thread, this figure shows all the locks that are owned by it, all the threads that are hard waiting on those locks in turn, and so on. In effect, each lock in the diagram is already waiting, whether directly or indirectly, for the root thread to eventually allow it to be free. If this thread needs to perform a hard wait on a lock, it can't be one that is in this tree. Doing so creates a loop, which is an indication of a deadlock situation. In summary, we can detect a deadlock by simply traversing this tree. If the lock is already in this tree, a loop is formed, and a deadlock condition occurs.
Figure 6-2. Completed thread wait tree
Using this algorithm, here is an implementation of a deadlock-detecting lock:
package javathreads.examples.ch06;
public class DeadlockDetectedException extends RuntimeException {
public DeadlockDetectedException(String s) {
package javathreads.examples.ch06;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
public class DeadlockDetectingLock extends ReentrantLock {
private static List deadlockLocksRegistry = new ArrayList( );
private static synchronized void registerLock(DeadlockDetectingLock ddl) {
if (!deadlockLocksRegistry.contains(ddl))
private static synchronized void unregisterLock(DeadlockDetectingLock ddl) {
if (deadlockLocksRegistry.contains(ddl))
private List hardwaitingThreads = new ArrayList( );
private static synchronized void markAsHardwait(List l, Thread t) {
if (!l.contains(t)) l.add(t);
private static synchronized void freeIfHardwait(List l, Thread t) {
if (l.contains(t)) l.remove(t);
private static Iterator getAllLocksOwned(Thread t) {
DeadlockDetectingLock current;
ArrayList results = new ArrayList( );
Iterator itr = deadlockLocksRegistry.iterator( );
while (itr.hasNext( )) {
current = (DeadlockDetectingLock) itr.next( );
if (current.getOwner( ) == t) results.add(current);
return results.iterator( );
private static Iterator getAllThreadsHardwaiting(DeadlockDetectingLock l) {
return l.hardwaitingThreads.iterator( );
private static synchronized
boolean canThreadWaitOnLock(Thread t, DeadlockDetectingLock l) {
Iterator locksOwned = getAllLocksOwned(t);
while (locksOwned.hasNext( )) {
DeadlockDetectingLock current =
(DeadlockDetectingLock) locksOwned.next( );
if (current == l) return false;
Iterator waitingThreads = getAllThreadsHardwaiting(current);
while (waitingThreads.hasNext( )) {
Thread otherthread = (Thread) waitingThreads.next( );
if (!canThreadWaitOnLock(otherthread, l)) {
return false;
return true;
public DeadlockDetectingLock( ) {
this(false, false);
public DeadlockDetectingLock(boolean fair) {
this(fair, false);
private boolean debugging;
public DeadlockDetectingLock(boolean fair, boolean debug) {
debugging = debug;
public void lock( ) {
if (isHeldByCurrentThread( )) {
if (debugging) System.out.println("Already Own Lock");
super.lock( );
freeIfHardwait(hardwaitingThreads, Thread.currentThread( ));
markAsHardwait(hardwaitingThreads, Thread.currentThread( ));
if (canThreadWaitOnLock(Thread.currentThread( ), this)) {
if (debugging) System.out.println("Waiting For Lock");
super.lock( );
freeIfHardwait(hardwaitingThreads, Thread.currentThread( ));
if (debugging) System.out.println("Got New Lock");
} else {
throw new DeadlockDetectedException("DEADLOCK");
public void lockInterruptibly( ) throws InterruptedException {
lock( );
public class DeadlockDetectingCondition implements Condition {
Condition embedded;
protected DeadlockDetectingCondition(ReentrantLock lock, Condition e) {
embedded = e;
public void await( ) throws InterruptedException {
try {
markAsHardwait(hardwaitingThreads, Thread.currentThread( ));
embedded.await( );
} finally {
freeIfHardwait(hardwaitingThreads, Thread.currentThread( ));
public void awaitUninterruptibly( ) {
markAsHardwait(hardwaitingThreads, Thread.currentThread( ));
embedded.awaitUninterruptibly( );
freeIfHardwait(hardwaitingThreads, Thread.currentThread( ));
public long awaitNanos(long nanosTimeout) throws InterruptedException {
try {
markAsHardwait(hardwaitingThreads, Thread.currentThread( ));
return embedded.awaitNanos(nanosTimeout);
} finally {
freeIfHardwait(hardwaitingThreads, Thread.currentThread( ));
public boolean await(long time, TimeUnit unit)
throws InterruptedException {
try {
markAsHardwait(hardwaitingThreads, Thread.currentThread( ));
return embedded.await(time, unit);
} finally {
freeIfHardwait(hardwaitingThreads, Thread.currentThread( ));
public boolean awaitUntil(Date deadline) throws InterruptedException {
try {
markAsHardwait(hardwaitingThreads, Thread.currentThread( ));
return embedded.awaitUntil(deadline);
} finally {
freeIfHardwait(hardwaitingThreads, Thread.currentThread( ));
public void signal( ) {
embedded.signal( );
public void signalAll( ) {
embedded.signalAll( );
public Condition newCondition( ) {
return new DeadlockDetectingCondition(this);
Before we go into detail on this deadlock-detecting lock, it must be noted that this listing has been cut down for this book. For the latest, fully commented version, including testing tools, please see the online examples, which include (as example 1) a class that can be used to test this implementation.
In terms of implementation, this class inherits from the
Lock interface, so it may be used anywhere that a
Lock object is required. Furthermore, deadlock
detection requires the registration of all locks involved in the
deadlock. Therefore, to detect a deadlock, replace all the locks with
this class, even the locks provided by the
keyword. It may not be possible to detect a loop if any of the locks
are unregistered.
To use this class, replace all instances of
ReentrantLock with
DeadlockDetectingLock. This slows down your
program, but when a deadlock is detected, a
is immediately thrown. Because of the performance implications of
this class, we do not recommend using it in a production environment:
use it only to diagnose occurrences of deadlock. The advantage of
using this class is that it detects the deadlock immediately when it
occurs instead of waiting for a symptom of the deadlock to occur and
diagnosing the problem then.
DeadlockDetectingLock class maintains two lists—a
deadlockLocksRegistry and a
hardwaitingThreads list. Both of these lists are
stored in thread-unsafe lists because external synchronization will
be used to access them. In this case, the external synchronization is
the class lock; all accesses to these lists come from synchronized
static methods. A single
list holds all deadlock-detecting locks that have been created. One
hardwaitingThreads list exists for each
deadlock-detecting lock. This list is not static; it holds all the
thread objects that are performing a hard wait on the particular
The deadlock locks are added and removed from the registry by using
registerLock() and
unregisterLock() methods. Threads are added and removed from
the hard waiting list using the
markAsHardwait() and
methods respectively. Since these methods are static—while the
list is not—the list must be passed as one of the parameters to
these methods. In terms of implementation, they are simple; the
objects are added and removed from a list container.
getAllLocksOwned() and
getAllThreadsHardwaiting() methods are used to get the two types of waiting subtrees we mentioned earlier. Using these subtrees, we can
build the complete wait tree that needs to be traversed. The
getAllThreadsHardwaiting() method simply returns
the list of hard waiting threads already maintained by the
deadlock-detecting lock. The list of owned locks is slightly more
difficult. The
getAllLocksOwned() method has to
traverse all registered deadlock-detecting locks, looking for locks
that are owned by the target thread. In terms of synchronization,
both of these methods are called from a method that owns the class
lock; as a result, there is no need for these private methods to be
canThreadWaitOnLock() method is used to traverse the wait tree,
looking to see if a particular lock is already in the tree. This is
the primary method that is used to detect potential deadlocks. When a
thread is about to perform a hard wait on a lock, it calls this
method. A deadlock is detected if the lock is already in the wait
tree. Note that the implementation is recursive. The method examines
all of the locks owned to see if the lock is in the first level of
the tree. It also traverses each owned lock to get the hard waiting
threads; each hard waiting thread is further examined recursively.
This method uses the class lock for synchronization.
With the ability to detect deadlocks, we can now override the
lock() method of the
ReentrantLock class. This new implementation is
actually not that simple. The
ReentrantLock class
is incredibly optimized—meaning it uses minimal
synchronization. In that regard, our new
method is also minimally synchronized.
The first part of the
lock() method is for nested locks. If the lock is
already owned by this thread, there is no reason to check for
deadlocks. Instead, we can just call the original
lock() method. There is no race condition for this case: only
the owner thread can succeed in the test for nested locks and call
the original
lock() method. And since there is no
chance that the owner of the lock will change if the owner is the
currently executing thread, there is no need to worry about the
potential race condition between the
isHeldByCurrentThread() and
super.lock() method calls.
The second part of the
lock() method is used to
obtain new locks. It first checks for deadlocks by calling the
canThreadWaitOnLock() method. If a deadlock is
detected, a runtime exception is thrown. Otherwise, the thread is
placed on the hard wait list for the lock, and the original
lock() method is called. Obviously, a race
condition exists here since the
lock() method is
not synchronized. To solve this, the thread is placed on the hard
wait list before the deadlock check is done. By simply reversing the
tasks, it is no longer possible for a deadlock to go undetected. In
fact, a deadlock may be actually detected before it happens due to
the race condition.
There is no reason to override the lock methods that accept a timeout
since these are soft locks. The interruptible lock request is
disabled by routing it to the uninterruptible version of the
lock() method.
Unfortunately, we are not done yet. Condition variables can also free
and reacquire the lock and do so in a fashion that makes our
deadlock-detecting class much more complex. The reacquisition of the
lock is a hard wait since the
await() method
can't return until the lock is acquired. This means
that the
await() method needs to release the
lock, wait for the notification from the
method to arrive, check for a potential deadlock, perform a hard wait
for the lock, and eventually reacquire the lock.
If you've already examined the code,
you'll notice that the implementation of the
await() method is simpler than we just discussed.
It doesn't even check for the deadlock. Instead, it
simply performs a hard wait prior to waiting for the signal. By
performing a hard wait before releasing the lock, we keep the thread
and lock connected. This means that if a later lock attempt is made,
a loop can still be detected, albeit by a different route.
Furthermore, since it is not possible to cause a deadlock simply by
using condition variables, there is no need to check for deadlock on
the condition variable side. The condition variable just needs to
allow the deadlock to be detected from the
method side. The condition variable also must place the thread on the
hard wait list prior to releasing the lock due to a race condition
with the
lock() method—it is possible to
miss detection of the deadlock if the lock is released first.
At this point, we are sure many readers have huge diagrams on their desk—or maybe on the floor—with thread and lock scenarios drawn in pencil. Deadlock detection is a very complex subject. We have tried to present it as simply as possible, but we are sure many readers will not be convinced that this class actually works without a few hours of playing out different scenarios. To help with this, the latest online copy of this class contains many simple test case scenarios (which can easily be extended).
To help further, here are answers to some possible questions. If you are not concerned with these questions, feel free to skip or skim the next section as desired. As a warning, some of these questions are very obscure, so obscure that some questions may not even be understood without a few hours of paper and pencil work. The goal is to work out the scenarios to understand the questions, which can hopefully be answered here.
We have stated that a deadlock condition is detected when a loop in the wait tree is detected. Is it really a loop? The answer is yes. This means that we have to be careful in our search or we can recursively search forever. Let's examine how the loop is formed from another point of view. Any waiting thread node can have only one parent lock node. That's because a thread can't perform a hard wait on more than one lock at a time. Any owned lock node can have only one parent thread node. That's because a lock can't be owned by more than one thread at a time. In this direction, only nodes connected to the top node can form the loop. As long as none of the owned lock nodes are connected to the top thread node, we don't have a loop. It is slightly more complicated than this, but we will address it with the next question.
Why are we using only the thread tree? What about the lock tree? These questions introduce a couple of definitions, so let's back up a few steps. To begin, we are trying to determine whether a thread can perform a hard wait on a particular lock. We then build a wait tree using this thread object as the top node; that's what we mean by the thread tree. However, the lock isn't independent. It is also possible to build a wait tree using the lock object as the top node, which we define as the lock tree. There may be other locks in the lock tree that could be in the thread tree, possibly forming a deadlock condition.
Fortunately, we don't have to traverse the lock tree because the thread tree is guaranteed to contain a root node as the top node. The top node of the thread tree is the currently running thread. It is not possible for this thread to be currently waiting on a lock since it wouldn't be executing the lock request. The top node of the lock tree is only the root node if the lock is not owned. For a loop to form, either the lock tree or the thread tree must be a subtree of the other. Since we know that the thread tree definitely contains the root node, only the lock node can be the subtree. To test for a subtree, we just need to test the top node.
Isn't marking the hard wait prior to checking for the deadlock condition a problem? Can it cause spurious deadlock exceptions? The answer is no. The deadlock condition will definitely occur since the thread will eventually perform the hard wait. It is just being detected slightly before it actually happens. On the other hand, our class may throw more than one deadlock exception once the deadlock has been detected. It must be noted that the purpose of this class is not to recover from the deadlock. In fact, once a deadlock exception is thrown, the class does not clean up after it. A retry attempt throws the same exception.
Can marking the hard wait first interfere with the deadlock check? By marking first, we are making a connection between the thread and the lock. In theory, this connection should be detected as a deadlock condition by the deadlock check. To determine if we're interfering with the deadlock check, we have to examine where the connection is made. We are connecting the lock node to the top thread node—the connection is actually above the top thread node. Since the search starts from the top thread node, it isn't able to detect the deadlock unless the lock node can be reached first. This connection is seen from the lock tree but is not a problem because that tree is not traversed. Traversals by other threads will be detected early as a deadlock condition since the hard wait will eventually be performed.
Can marking the hard wait first cause an error condition in other threads? Will it cause a loop in the trees? We need to avoid a loop in the wait trees for two reasons. First, and obviously, is because it is an indication of a deadlock condition. The second reason is because we will be searching through the wait trees. Recursively searching through a tree that has a loop causes an infinite search (if the lock being sought is not within the loop).
The answer to this question is no, it can't cause an error condition. First, there is no way to enter the loop from a thread node that is not within the loop. All thread nodes within the loop are performing a hard wait on locks within the loop. And all lock nodes within the loop are owned by thread nodes within the loop. Second, it is not possible to start from a thread node that is within the loop. With the exception of the top thread node, all the thread nodes are performing a hard wait. To be able to perform the deadlock check, a thread cannot be in a wait state and therefore can't be in the wait tree. If a loop is formed, only the thread represented by the top thread node can detect the deadlock.
This answer assumes that a deadlock-detected exception has never been thrown; this class is not designed to work once such an exception is thrown. For that functionality, consider using the alternate deadlock-detecting class that is available online.
How can the simple solution of switching the
"thread owns the lock" to the
"thread hard waiting for lock" work
for condition variables? Admittedly, we did a bit of hand
waving in the explanation. A better way to envision it is to treat
the operations as being separate entities—as if the
condition variable is releasing and
reacquiring the lock. Since the reacquisition is mandatory (i.e., it
will eventually occur), we mark the thread for reacquisition before
we release the lock. We can argue that switching the ownership state
to a hard wait state removes the connection from the thread tree,
making detection impossible. This is just an artifact of examining
the wait tree from the condition variable's
perspective. When the
lock() method is called at
a later time, we will be using a different thread object as the top
node, forming a different wait tree. From that perspective, we can
use either the ownership state or hard wait state for the detection
of the deadlock.
Why don't we have to check for potential
deadlocks on the condition variable side? It is not
necessary. Marking for the wait operation prior to unlocking works in
a pseudo atomic manner, meaning that it is not possible for another
thread to miss the detection of the deadlock when using the
lock() method. Since it is not possible to create
a new deadlock just by using condition variables, we
don't need to check on this end. Another explanation
is that there is no need to check because we already know the answer:
the thread is capable of performing a hard wait because it has
previously owned the lock and has not had a chance to request
additional locks.
Isn't marking for the hard wait prior to
performing the
await()operation a problem? Can it cause spurious deadlock exceptions? Can
it cause an error condition in other threads? Two of these
questions are very similar to the questions for the
lock() method side. The extra question here addresses the issue
of interfering with the deadlock check. That question
doesn't apply on the
method side because we do not perform a deadlock check on the
condition variable side.
However, the answers to the other questions are not exactly the same as before. In this case, the thread is performing a hard wait on the lock before the thread releases ownership of the lock. We are creating a temporary loop—a loop that is created even though the deadlock condition does not exist. This is not a case of detecting the deadlock early—if the loop were detected, the deadlock detected would be incorrect.
These three questions can be answered together. As with the error
question on the
lock() method side, it is not
possible to enter the loop from a thread node outside of the loop.
Second, the one thread node that is within this small loop is not
performing a deadlock check. And finally, any deadlock check does not
traverse the lock tree. This means that an error condition
can't occur in another thread and that detecting a
false deadlock condition also can't occur in another
thread. Of course, eventually it would be possible to get to the lock
node externally, but by then, the loop would have been broken. It is
not possible for another thread to own the lock unless the condition
variable thread releases it first.
To review, we are traversing the thread tree to check whether the lock tree is a subtree. Instead of recursively traversing from the thread tree, isn't it easier to traverse upward from the lock tree? Our answer is maybe. We simply list the pluses and minuses and let the reader decide. Two good points can be made for traversing from the lock tree. First, the search is not recursive. Each node of the lock tree has only one parent, so going upward can be done iteratively. Second, moving upward from lock node to parent thread node does not need any iterations—the owner thread object is already referenced by the lock object. On the other hand, moving downward from the thread node to the lock node requires iteration through the registered locks list.
Unfortunately, there are two bad points to traversing upward from the lock tree. First, moving upward from the thread node to the lock node on which it is performing the hard wait is incredibly time-consuming. We need to iterate through the registered locks list to find the hard wait lists, which we must, in turn, iterate through to find the lock node. In comparison, moving downward from the lock node to the thread node is done by iterating through one hard wait list. And it gets worse. We need to iterate through all of the hard wait lists. By comparison, we need to iterate only through the hard wait lists in the wait tree in our existing implementation. This one point alone may outweigh the good points.
The second bad point stems from the techniques that we use to solve the race conditions in the lock class. The class allows loops to occur—even temporarily creating them when a deadlock condition does not exist. Searching from a lock node that is within a loop—whether recursively downward or iteratively upward—does not terminate if the top thread node is not within the loop. Fortunately, this problem can be easily solved. We just need to terminate the search if the top lock node is found. Also note that finding the top lock node is not an indication of a deadlock condition since some temporary loops are formed even without a deadlock condition.
To review, we are traversing the thread tree instead of the lock tree because the top thread node is definitely the root node. The top lock node may not be the root node. However, what if the top lock node is also the root node? Isn't this a shortcut in the search for a deadlock? Yes. It is not possible for the lock tree to be a subtree of the thread tree if the top lock node is a root node. This means we can remove some calls to the deadlock check by first checking to see if the lock is already owned. This is an important improvement since the deadlock check is very time-consuming.
However, a race condition exists when a lock has no owner. If the lock is unowned, there is no guarantee that the lock will remain unowned during the deadlock check. This race condition is not a problem since it is not possible for any lock in the wait tree to be unowned at any time during the deadlock check; the deadlock check may be skipped whether or not the lock remains unowned.
This shortcut is mostly for locks that are infrequently used. For frequently used locks, this shortcut is highly dependent on the thread finding the lock to be free, which is based on the timing of the application.
The modification with some deadlock checking removed is available online in our alternate deadlock-detecting lock.
The deadlock-detecting lock disallows interruptible locking
requests. What if we do not agree with this
compromise? There are only a
few options. Disallowing the interrupt was the easiest compromise
that works for the majority of the cases. For those readers who
believe an interruptible lock should be considered a soft lock, the
change is simple—just don't override the
lockInterruptibly() method. And for those readers
who believe that an interruptible lock should be considered a hard
lock while still not compromising interrupt capability, here is a
modified version of the method:
public void lockInterruptibly( ) throws InterruptedException {
if (isHeldByCurrentThread( )) {
if (debugging) System.out.println("Already Own Lock");
try {
super.lockInterruptibly( );
} finally {
Thread.currentThread( ));
markAsHardwait(hardwaitingThreads, Thread.currentThread( ));
if (canThreadWaitOnLock(Thread.currentThread( ), this)) {
if (debugging) System.out.println("Waiting For Lock");
try {
super.lockInterruptibly( );
} finally {
Thread.currentThread( ));
if (debugging) System.out.println("Got New Lock");
} else {
throw new DeadlockDetectedException("DEADLOCK");
This change is also provided online in our alternate
deadlock-detecting lock class. In terms of implementation, it is
practically identical to that of the
method. The difference is that we now place all lock requests within
try-finally clause. This allows the method to
clean up after the request, regardless of whether it exits normally
or by exception.
The deadlock-detecting lock regards all lock requests with a timeout as soft locks. What if we do not agree with this premise? This topic is open to debate. While an application that uses timeouts should have an exit strategy when the timeout occurs, what if the exit strategy is to inform the user and then simply retry? In this case, deadlock could occur. Furthermore, at what point is retrying no longer tolerable? When the timeout period is more than an hour? A day? A month? Obviously, these issues are design-specific.
Here is an implementation of the
tryLock() method
that treats the request as a soft wait—but only if it is less
than a minute:
public boolean tryLock(long time, TimeUnit unit)
throws InterruptedException {
// Perform operation as a soft wait
if (unit.toSeconds(time) < 60) {
return super.tryLock(time, unit);
if (isHeldByCurrentThread( )) {
if (debugging) System.out.println("Already Own Lock");
try {
return super.tryLock(time, unit);
} finally {
Thread.currentThread( ));
markAsHardwait(hardwaitingThreads, Thread.currentThread( ));
if (canThreadWaitOnLock(Thread.currentThread( ), this)) {
if (debugging) System.out.println("Waiting For Lock");
try {
return super.tryLock(time, unit);
} finally {
Thread.currentThread( ));
if (debugging) System.out.println("Got New Lock");
} else {
throw new DeadlockDetectedException("DEADLOCK");
This change is also provided in the online examples as an alternative
to the deadlock-detecting lock class (including a testing program,
which is example 2 in this chapter). Its implementation is
practically identical to that of the
method. Again, the difference is that we now place all lock requests
within a
try-finally clause. This allows the
method to clean up after the request, regardless if it exits normally
or by exception. This example treats the operation as a soft wait for
requests that are under a minute. The request is treated as a hard
wait otherwise. We leave it up to you to modify the code to suit your
needs. One alternate solution could be to use a different time period
to separate soft and hard wait lock operations; this time period
could also be calculated depending on conditions in the program.
Another alternate solution could be for the
trylock() method to return false instead of throwing the
deadlock-detected exception.
While the deadlock-detecting lock is well-designed for detecting the deadlock condition, the design for reporting the condition is pretty weak. Are there better options? This is actually intentional. This class is not designed to be used in a production environment. Searching for deadlocks can be very inefficient—this class should be used only during development. In fact, most readers will probably not use this class at all. The main purpose of this class is so that we can understand deadlocks—how to detect them and, eventually, how to prevent them.
For those who insist on using the deadlock-detecting lock in a production environment, there are a few options. The class can be designed to fail fast—meaning that if a deadlock is detected, the class could throw the exception for every invocation, regardless of whether the request is involved in the deadlock or not. Another option is for the class to report the condition in a manner that allows the program to shut down properly. A third, and not recommended, option is to allow the class to continue functioning. The first and third options are provided as conditional code in the alternate online example.
This topic of deadlock detection seems to be incredibly
complex. In fact, the discussion on the theory and implementation is
more than twice as long as the code itself. Is this topic really that
complex? The concept of deadlock detection is complex, but
there is another reason why this class is even more complex. The
implementation of this class is accomplished by minimal
synchronization. This is mainly because the
ReentrantLock class is implemented with minimal
synchronization, making the class implementation more complex.
Whenever multiple threads compete for a scarce resource, there is the danger of starvation, a situation in which the thread never gets the resource. In Chapter 9, we discuss the concept in the context of CPU starvation: with a bad choice of scheduling options, some threads never have the opportunity to become the currently running thread and suffer from CPU starvation.
Lock starvation is similar to CPU starvation in that the thread is unable to execute. It is different from CPU starvation in that the thread is given the opportunity to execute; it is just not able to because it is unable to obtain the lock. Lock starvation is similar to a deadlock in that the thread waits indefinitely for a lock. It is different in that it is not caused by a loop in the wait tree. Its occurrence is somewhat rare and is caused by a very complex set of circumstances.
Lock starvation occurs when a particular thread attempts to acquire a lock and never succeeds because another thread is already holding the lock. Clearly, this can occur on a simple basis if one thread acquires the lock and never releases it: all other threads that attempt to acquire the lock never succeed and starve. Lock starvation can also be more subtle; if six threads are competing for the same lock, it's possible that five threads will hold the lock for 20% of the time, thus starving the sixth thread.
Lock starvation is not something most threaded Java programs need to consider. If our Java program is producing a result in a finite period of time, eventually all threads in the program will acquire the lock, if only because all the other threads in the program have exited. Lock starvation also involves the question of fairness: at certain times we want to make sure that threads acquire the locks in a reasonable order so that one thread won't have to wait for all other threads to exit before it has its chance to acquire the lock.
Consider the case of two threads competing for a lock. Assume that thread A acquires the object lock on a fairly periodic basis, as shown in Figure 6-3.
Figure 6-3. Call graph of synchronized methods
Here's what happens at various points on the graph:
T0: At time T0, both thread A and thread B are able to run, and thread A is the currently running thread.
T1: Thread A is still the currently running thread, and it acquires the object lock when it enters the synchronized block.
T2: A timeslice occurs; this causes thread B to become the currently running thread.
T3: Very soon after becoming the currently running thread, thread B attempts to enter the synchronized block. This causes thread B to block. That allows thread A to continue to run; thread A continues executing in the synchronized block.
T4: Thread A exits the synchronized block. Thread B could obtain the lock now, but it is still not running on any CPU.
T5: Thread A once again enters the synchronized block and acquires the lock.
T6: Thread B once again is assigned to a CPU. It immediately tries to enter the synchronized block, but the lock for the synchronized block is once again held by thread A. So, thread B blocks again. Thread A then gets the CPU, and we're now in the same state as we were at time T3.
It's possible for this cycle to continue forever such that thread B can never acquire the lock and actually do useful work.
Clearly, this example is a pathological case: CPU scheduling must occur only during those time periods when thread A holds the lock for the synchronized block. With two threads, that's extremely unlikely and generally indicates that thread A is holding the lock almost continuously. With several threads, however, it's not out of the question that one thread may find that every time it is scheduled, another thread holds the lock it wants.
Synchronized blocks within loops often have this problem:
while (true) {
synchronized (this) {
// execute some code
At first glance, we might expect this not to be a problem; other threads can't starve because the lock is freed often, with each iteration of the loop. But as we've seen, this is not the case: unless another thread runs during the short interval between the end of the synchronized block (when the lock is released) and the beginning of the next iteration of the loop (when the lock is reacquired), no other thread will be able to acquire the lock.
There are two points to take away from this:
Acquisition of locks does not queue
When a thread attempts to acquire a lock, it does not check to see if another thread is already attempting to acquire the lock (or, more precisely, if another thread has tried to acquire the lock and blocked because it was already held). In pseudocode, the process looks like this:
while (lock is held)
wait for a while
acquire lock
For threads of equal priority, there's nothing in this process that prevents a lock from being granted to one thread even if another thread is waiting.
Releasing a lock does not affect thread scheduling
When a lock is released, any threads that were blocked waiting for that lock could run. However, no actual scheduling occurs, so none of the threads that have just moved into the runnable state are assigned to the CPU; the thread that has just released the lock keeps access to the CPU. This can be different if the threads have different priorities or are on a multiprocessor machine (where a different CPU might be idle).
Nonetheless, lock starvation remains, as might be guessed from our example, something that occurs only in rare circumstances. In fact, each of the following circumstances must be present for lock starvation to occur:
Multiple threads are competing for the same lock. This lock becomes the scarce resource for which some threads may starve.
The results that occur during this period of contention must be interesting to us. If, for example, we're calculating a big matrix, there's probably a point in time at the beginning of our calculation during which multiple threads are competing for the same lock and CPU. Since all we care about is the final result of this calculation, it doesn't matter to us that some threads are temporarily starved for the lock: we still get the final answer in the same amount of time.We're concerned about lock starvation only if there's a period of time during which it matters whether the lock is allocated fairly.
All of the properties of lock starvation stem from the fact that a thread attempting to acquire a lock checks only to see if another thread is holding the lock—the thread knows nothing about other threads that are also waiting for the lock. This behavior in conjunction with properties of the program such as the number of threads, their priorities, and how they are scheduled manifests itself as a case of lock starvation.
Fortunately, this problem has already been solved by the
class. If we're in one of the rare situations where
lock starvation can occur, we just need to construct a
ReentrantLock object where the fairness flag is
set to true. Since the
ReentrantLock class with
its fairness flag set grants the lock on very close to a first-come,
first-served basis, it is not possible for any thread to be starved
for a lock regardless of the number of threads or how
they're written.
Unfortunately, the downside to using the
ReentrantLock class in this manner is that we are
affecting the scheduling. We discuss how threads are scheduled in
Chapter 9, but in general, threads have a
priority, and the higher-priority threads are given the CPU more
often than low-priority threads. However, the
ReentrantLock class does not take that into
account when issuing locks: locks are issued first-come, first-served
regardless of the thread's priority.
Programs that set thread priorities do so for a reason. The reason
could be because the developer wanted to have the scheduler behave in
a certain manner. While using the fair flag in the
ReentrantLock class may prevent lock starvation,
it may also change the desired scheduling behavior.
Lock starvation is a rare problem; it happens only under very
distinct circumstances. While it can be easily fixed with the
ReentrantLock class, it may also change some of
these desired circumstances. On the other hand, if priorities and
scheduling are not a concern, the
class provides a very simple and quick fix.
Generally, reader/writer locks are used when there are many more readers than writers; readers also tend to hold onto the lock for a longer period of time than they would a simple lock. This is why the reader/writer lock is needed—to share data access during the long periods of time when only reading is needed. Unfortunately, readers can't just grab the lock if the lock is held for reading by another thread. If many readers were holding the lock, it would be possible for many more readers to grab the lock before the first set of readers finished. Many more readers could then obtain the lock before the second set of readers finished. This would prevent the writer from ever obtaining the lock.
To solve this, the reader/writer lock does not grant the read lock to
a new thread if there is a writer waiting for the lock. Instead it
places the reader into a wait state until the first set of readers
frees the lock. Once the first set of readers have completed, the
first writer is given exclusive access to the lock. When that writer
completes, the
ReentrantReadWriteLock class
consults its fairness flag to see what to do next. If the fairness
flag is true, the thread waiting longest—whether a reader or a
writer—is granted the lock (and multiple readers can get the
lock in this case). If the fairness flag is false, locks are
granted arbitrarily.
The strong integration of locks into the Java language and API is very useful for programming with Java threads. Java also provides very strong tools to allow thread programming at a higher level. With these tools, Java provides a comprehensive library to use for your multithreaded programs.
Even with this library, threaded programming is not easy. The developer needs to understand the issues of deadlock and starvation, in order to design applications in a concurrent fashion. While it is not possible to have a program threaded automatically—with a combination of using the more advanced tools and development practices, it can be very easy to design and debug threaded programs.
Here are the class names and Ant targets for the examples in this chapter:
|Main Java class
|Ant target
|Deadlock-detecting Lock
|Alternate Deadlock-detecting Lock
Three tests are available for each example. The first test uses two threads and two competing locks. The second test uses three threads and three competing locks. The third test uses condition variables to cause the deadlock. Test numbers are selected with this property:
<property name="DeadlockTestNumber" value="2"/>
Scott Oaks is a Java Technologist at Sun Microsystems, where he has worked since 1987. While at Sun, he has specialized in many disparate technologies, from the SunOS kernel to network programming and RPCs.
Return to ONJava.com.
Copyright © 2009 O'Reilly Media, Inc.


text:
New Toys For Summer 2012
The Great Outdoors: 10 Summer Toys to Get Kids Up and Out!
Photo 1 of 11
ADVERTISEMENT ( more slides)
The Great Outdoors: 10 Summer Toys to Get Kids Up and Out!
Warm weather's not just an opportunity to shed your jacket, but to get the kids up, moving, and outside. While the sun may be all it takes to get mama outdoors, tots often need a little enticement — that's where the toys come into play. We've checked out the hottest new toys of the season and have narrowed down our favorites that will have lil ones begging to enjoy the fresh air. Check them out!


text:
it says he can be traded alone anytime, doubt seeing anyone of value comming back forth 10 million
have to wait 60 days for some big tickets
I tweeted Brian Getzlinger who is a frequent guest on TKB radio led by Knicks reporter, Tommy Dee. Brian G told me this after i asked if we could realistically trade Bargnani after July 10...
@hoopscritic: @PRussomanno just checked. It is 60 days but only if he player's salary is aggregated with another player's. can be traded alone anytime
So for all of you who think the Bargnani deal is a bridge to a bigger deal, well it is possible. We will see.
"The Knicks are back" - Amare
it says he can be traded alone anytime, doubt seeing anyone of value comming back forth 10 million
have to wait 60 days for some big tickets
i still say the knicks should keep him until 2015. The knicks wont get anything decent for him look what the raptors took basically a late first and 2 bad contracts. If the knicks are smart.... and they will hold him and in 2015 use his contract alongside, amare's and Tyson's to go after younger FA's with offer for Max Salaries.
Even if the knicks strike out on their first choices it will fu*k up a whole bunch of other team's cap situations by forcing them to pay max money on one player. The second choices aren't bad either. Plus the knicks would have shumps bird rights and can sign him to something fair as well.
Why move him? Just think what if his play was a vince Carter move? And lack of motivation, we can get a major upgrade if he can still bring it. People thought vince was done because he was averaging the teens those last few months in Toronto. Traded to a nets team that weren't in the playoffs at the time of the trade and carries them to the playoffs then the next year he led the playoffs in scoring.... People get tired of Toronto and a whole lot of people here will be eating their crow if this pans out
Sent from my SPH-L720 using Tapatalk 2
The last 2 seasons Toronto been trying to move Bargani, but couldnt bc Bargani performance is only worth $3M to $4M per.
Our Knicks organization is still the gullible-fool to take on over-paid players contracts that are twice the salary of the players worth.
Being we are New York BIG-APPLE the capital of tourist where a 23 win season Knicks team could sell-out 30 games out of 41 games in MSG, making a decent profit each win or lose season by keeping our cap above $75M per gives the Knicks owner a team worth $400M to $500M in ASSETS .. having a half a billion asset in just one of the many organization u own puts u where in our society???
"The Knicks are back" - Amare
I know i too have been a culprit of getting rid of Bargniani, but what if he still has game.....he had a great offensive game at one time
Like you said there was a lot there at one time...in 2010 he would have been a dream to have had in Dantoni' offense.
But like Stat he has not done Jack since then...but also like Amare he only has 2 more years like 90% of our team so lets just role with it and maybe we are surprised if not...well he's off the books and did not hurt our cap situation...just our picks and those to me are very very precious.
"I'd Rather Melo shoot with 3 men on him than Jefferies shotting wide open"
-Jeff Van Gundy
Yeah but our picks were crappy ones anyways. Our first rounder was orignally OKC's pick if i'm right. So thats like a 25-28th pick imo. And the 2nd round picks usually don't pan out in the NBA
I don't want us to trade him. I'd rather find any possible way to dump Amare'


text:
Celebrating 10 years, BATHORY decided to put out a release containing their most loved material. And what better way to get the ideal tracking list together than to ask the fans themselves. Word got around and in due time a list of the tracks the fans felt should represent the first 10 years of the bands could be compiled.
The problem was the mixture of styles, how to best nail the running order, and what about the length of some of the tracks chosen. In order to keep within the brim of a CD length vise, several tracks - it seemed - would have to be left out due to the fact that many songs most wanted by the fans were close to ten minutes long. The solution was either a double CD or a Volume I and Volume II twin-release.
The latter choice was deemed best, dubbed JUBILEUM VOLUME I and JUBILEUM VOLUME II. For the fans delight, previously unreleased material such as Rider at the Gate of Dawn, Burnin Leather and Crawl to Your Cross, material from BATHORYs pre-album days such as You dont move me and Die in Fire, as well as hard-to-get-by stuff like the original versions of The Return of The Darkness and Evil and Sacrifice, would grace the tracking list of both CDs. A true testament!


text:
Every product will empower you to be more relaxed, smiling, joyful, and flowing in harmony with the Life Force. Each video, book, or audio course will assist your authentic Self to fulfill worldly needs and relations; feel the profound sexual pleasure of being a radiant, healthy body; express your unique virtues; complete your soul destiny; realize peace experience eternal life flowing in this human body Now.
Use our products for one whole year we guarantee youll be 100% delighted and satisfied with the results. Return any product in good condition for immediate refund.
Our 256 bit SSL encryption means your personal information is 100% secure.


text:
5 results sorted by popularity
|Quick Questions
|Who was King James, and what authority did he have to produce a Bible?
|Magazine Articles
|The Great Divorce
|Quick Questions
|Why did Henry VIII need a dispensation to marry his brother's widow, Catherine of Aragon?
|Quick Questions
|Was the Anglican schism brought about because Church officials told Henry VIII to have an affair when he requested an annulment?
|Magazine Articles
|Mary Tudor ("Bloody Mary")


text:
Stiga Master Series ST1100 Indoor Table Tennis Conversion Top
NOW: $129.99 (13% off!)
Was: $149.99*
Product Information:
Place the Stiga® Master Series ST1100 Indoor Table Tennis Conversion Top on your billiard table to change up the tempo. This is a surface top only that conveniently sits on top of most 7' and 8' tables for total family fun. The ˝" top is lined with sponge-rubber strips to protect your table and eliminate shifting. The Stiga® ST1100 Table Tennis Conversion Top is great when space is limited but competitive spirits are high.
Click here for additional information relating to the Manufacturer's Warranty.
- Conversion top table tennis table
- Fits most 7' and 8' tables
- Hinged, 4-piece design
- Fits in most cars and SUVs
- Easy to transport and store
- Sponge-rubber strips protect table
- ˝" top
- Smooth and durable silk-screened striping
- Table Dimensions: 9' x 5' x ˝"
- Packaging Dimensions: 57.50" x 34" x 3"
- Packaging Weight: 100 lbs.
- Net and post set not included
- Surface top only
- 1-year limited manufacturer's warranty
- Style: T8712
- Stiga
Click here for additional information relating to the Manufacturer's Warranty.
Country of Origin: ChinaWeb ID: 12152583
Customer Reviews:
Rated 3.4 out of 5 by 37 reviewers.
Rated 1 out of 5 by Trapz Terrible Terrible product and horribly designed. The boards are too heavy for the hinges so after the 2nd or 3rd use count on the screws/hinges coming off. Just not a good product. September 19, 2016
Rated 5 out of 5 by Jody2 Great product for the price Works great right on top our pool table. Kids are loving it for a quick change from pool. Sturdy enough for its use at the price. June 13, 2016
Rated 5 out of 5 by Isk8r Just what we were looking for! Sits right on top of our pool table. Gives us a change of pace from the pool table. Easy to set up and take down. January 12, 2016
Rated 5 out of 5 by bum1 Great table. Easy to set-up for use. Awesome table. My kids love it. Its really easy to set-up. Does take two people or you can scratch your pool table. A bit heavy but probably necessary. January 11, 2016
Rated 5 out of 5 by Happymom Should have bought it sooner! Love this table! It's so much fun! It's perfect for family fun if you are expecting a professional table this isn't for you. However, if you want an affordable and easy to install table this one is a winner! Our family is enjoying it! January 11, 2016
Rated 5 out of 5 by FaF Ping pong table We play everyday! My sons are 12 and 14 yrs old and can't stop playing ping pong!! January 11, 2016
Rated 3 out of 5 by KK Net included would have been more helpful! As I did not read the fine print, I did not see that the table did not come with a net. Looking at a picture of the product, I would have assumed everything in the picture came in the box! Otherwise, you get what you get for the price of it. January 10, 2016
Rated 1 out of 5 by Disappointed Junk Tiny screws hold the hinges in particle board -- guaranteed to pull out during set up or take down. Plan on having a four piece ping pong table in short order if you use this and your pool table regularly (moving the hinges to fresh wood to screw into will only work so long after which there's no solid wood left). It would be cheaper & easier to paint a couple of pieces of laminated plywood & make your own -- screws will hold tight in that much better & the laminated wood holds level much better. With use, just setting there, this will sag, even after the very first setup before play starts! -- the metal reinforcements do not work well at all. Underlying supports (blocks of wood, old CD cases, etc.) are necessary to get this to approach level on a pool table. Ultimately, you'll need to get separate plywood to support this.... Paint rubs off on the balls, your fingers, etc. - even after cleaning. After a couple of minutes any new ball will be spotted. If you lean on it at all, your hand/fingers will be smudged--and that will rub off on your clothes. Even if you planned on using this as a top on homemade legs the poor paint quality is a major deterrent. I have to assume that Stiga uses the same paint across its product line--I'll NEVER buy their product again. Ever. I cannot believe any regular user of this can be happy with it. Stiga should be ashamed to put their name on this. January 9, 2016
Rated 2 out of 5 by Katie Would be nice if there was a net included! Would be nice if there was an actual net included! So Christmas Eve, we set up the table and find no NET! Yes, it said net wasn't included but no one bothered to tell me when I was forking out all that money! And the pictured showed the net. I guess marketing lie! December 25, 2015
Rated 1 out of 5 by Dddd Just horrible Quite possibly the worst thing I've ever bought. Hinges in middle are awkward to set up, not support in middle, sags in any sections over 2ft span. Hinges will stay fixed in the mdf for a day maybe. Just a horrible design. Had high hopes. December 25, 2015


text:
Sakapfet (What's Happening)
Now, having served as a bridge from post-disaster relief to longer-term reconstruction, the Fund has stepped back, empowering Haiti to chart its own successful future.
The Clinton Bush Haiti Fund Commits Its Remaining Funds
Final grants promote economic opportunity as Haitians transition to long-term reconstruction.
Progress Continues as the Clinton Bush Haiti Fund Steps Back
Root Capital CEO Willy Foote thanks the Fund for "serving as a catalyst, for helping build Haitian agriculture that empowers small-scale farmers and is truly sustainable in the long-term."
Executive Message
We have used these generous donations to help Haitians transform their own country. In the immediate aftermath of the earthquake, the Fund supported emergency needs. We then transitioned to promoting smart, sustainable economic development.
Read More »
Watch our video to see how your donations are helping Haiti chart its own bright future.


text:
Welcome to the CRG Discussion Forum!Forum registration problems: Make sure you enter your email correctly and you check your spam box first. *Then* email KurtS2@gmail for help.
Tom I have a question for you... I have detailed pictures of my former 69 RS / SS L 78 numbers, early LA car. Plus some pictures from the original owner back in the day. I thought it could be useful for the registry. But I don't know if because I don't own it any more if I'm crossing a line. Terry


text:
Home List of Titles Bacterial retention on superhydrophobic titanium surfaces fabricated by femtosecond laser ablation
Please use this identifier to cite or link to this item: http://hdl.handle.net/1959.3/167132
- Title
- Bacterial retention on superhydrophobic titanium surfaces fabricated by femtosecond laser ablation
- Author(s)
- Fadeeva, Elena; Truong, Vi Khanh; Stiesch, Meike; Chichkov, Boris N.; Crawford, Russell J.; Wang, James; Ivanova, Elena P.
- Abstract
- Two-tier micro- and nanoscale quasi-periodic self-organized structures, mimicking the surface of a lotus Nelumbo nucifera leaf, were fabricated on titanium surfaces using femtosecond laser ablation. The first tier consisted of large grainlike convex features between 10 and 20 μm in size. The second tier existed on the surface of these grains, where 200 nm (or less) wide irregular undulations were present. The introduction of the biomimetic surface patterns significantly transformed the surface wettabilty of the titanium surface. The original surface possessed a water contact angle of θW 73 ± 3°, whereas the laser-treated titanium surface became superhydrophobic, with a water contact angle of θW 166 ± 4°. Investigations of the interaction of S. aureus and P. aeruginosa with these superhydrophobic surfaces at the surface−liquid interface revealed a highly selective retention pattern for two pathogenic bacteria. While S. aureus cells were able to successfully colonize the superhydrophobic titanium surfaces, no P. aeruginosa cells were able to attach to the surface (i.e., any attached bacterial cells were below the estimated lower detection limit).
- Publication type
- Journal article
- Research centre
- Swinburne University of Technology. Faculty of Life and Social Sciences
- Research centre
- Swinburne University of Technology. Faculty of Engineering and Industrial Sciences. Industrial Research Institute Swinburne
- Source
- Langmuir, Vol. 27, no. 6 (Mar 2011), pp. 3012-3019
- Publication year
- 2011
- FOR Code(s)
- 0306 Physical Chemistry (Incl. Structural); 0903 Biomedical Engineering; 0904 Chemical Engineering
- Keyword(s)
- Bacteria; Femtosecond laster ablation; Nanostructures; Titanium surfaces
- Publisher
- American Chemical Society
- 0743-7463
- Publisher URL
- Copyright
- Copyright © 2011 American Chemical Society.
- Peer reviewed