ورود

View Full Version : سوال: آیا این تحلیل درست و کامل است؟



قله بلند
سه شنبه 08 دی 1388, 18:10 عصر
با سلام
در این تاپیک قصد دارم تا یک برنامه ساده را که از دو نخ استفاده می کند، تحلیل کنم. یکی از نخ ها، نخ main و نخ دوم یک نخ بی نام که در کلاسی به نام counter ایجاد می شود. داستان را از جایی شروع می کنم که برنامه اجرا می شود.

1-تابع main اجرا می شود. یعنی نخ مربوط به برنامه اصلی، کارش را شروع می کند.
2-نخ جدید ساخته می شود ولی هنوز قابل اجرا نیست.
3-تابع start ، نقطه شروع را برای اجرای نخ تازه، معین می کند.
4-برنامه به تابع main باز می گردد.
5-دستورSystem.out.println(t) اجرا می شود.
6-نخ اصلی با یک وقفه 2 ثانیه ای رو به رو شده و در صف انتظار قرار می گیرد. حالا نوبت به اجرای نخ جدید می رسد.
7-برنامه به تابع run می رود و عدد 1 چاپ می شود. سپس با یک وقفه 2 ثانیه ای برخورد کرده و در صف انتظار قرار می گیرد.
8-2 ثانیه برای نخ main سپری شده و دستور System.out.println(t) اجرا می شود.
9-2 ثانیه مربوط به نخ جدید تمام شده و عدد 2 چاپ می شود. دوباره یک وقفه 2 ثانیه ای کار حلقه را عقب می اندازد. برنامه صبر می کند و سپس از حلقه خارج شده و دستور بعد از catch اجرا می شود. یعنی +چاپ می شود.
10- برنامه تمام می شود و نخ اصلی نیز می میرد.

سوال: آیا این تحلیل، کاملاً واقعی است یا یک جور احتمالات است؟ چون اجرای دستورات دیگر نیز زمانبر است و دقیقاً نمی توان گفت که مثلاً 2 ثانیه ای صبر کرده ایم.

نکته: وقتی به جای دستور Thread.sleep(2000) در نخ اصلی، از دستور t.stop(); استفاده کردم، اصلاً نخ جدید اجرا نشد و کاملاً از بین رفت و زمانیکه از دستور Thread.currentThread().stop(); استفاده کردم، دستورات بعدی در نخ اصلی دیگر اجرا نشد. یعنی تابع stop()، نخ زنده را می میراند.
import java.lang.Runnable;
class Counter implements Runnable {
public int count = 1;
public void run()
{
while (count < 3)
{
try
{
System.out.println(count);
Thread.sleep(2000);
}
catch (InterruptedException e)
{
}
count++;
} System.out.println("+");
}
}
public class B
{
public static void main(String args[]) throws Exception
{
Runnable r = new Counter();
Thread t = new Thread(r);
t.start();
System.out.println(t);
Thread.sleep(2000);
System.out.println(t);
}
}

قله بلند
پنج شنبه 10 دی 1388, 00:34 صبح
با سلام.
من راجع به استفاده از تابع stop به نتایجی رسیده ام که در اینجا ذکر می کنم. در پست قبلی گذری به این موضوع زده بودم. شما فرض کنید که در تابع main، بعد از
Thread.sleep(2000);دستور زیر را اضافه کنیم.
t.stop();این تابع، به محض اینکه اجرا شود، اجرای نخ تولید شده را(در هر نقطه ای که باشد) به طور کامل متوقف می کند یعنی آن را می کُشد. پس هر گاه به این دستور رسیدیم، فقط نخ اصلی که همان تابع main باشد اجرا می شود. استفاده از این دستور، خطرناک است. چرا؟
زیرا این تابع به صورت ذاتی خطرناک است. از کار انداختن یک نخ باعث بازگشایی تمامی پویشگرهایی می شود که قفل هستند.( این پویشگرها به عنوان استثنائ ThreadDeath که پشته را گسترش می دهند بازگشایی می شوند.) اگر هر کدام از اشیائی که سابقاً به وسیله این پویشگرها محافظت می شدند در حالتی ناجور و متناقض به سر ببرند، نخ های دیگر ممکن است این اشیاء را در حالتی ناجور مشاهده کنند. چنین اشیائی که توصیف آنها گفته شد، خراب هستند. زمانیکه نخ ها روی اشیاء معیوب و خراب کار می کنند رفتار دلخواه نتیجه این عمل خواهد بود. این رفتار ممکن است ماهرانه باشد و یافتن آن نیز سخت و مشکل باشد، ممکن است این رفتار مشخص و معین نیز باشد. برخلاف استثنائات کنترل نشده دیگر، ThreadDeathآهسته نخ ها را می کشد، بنابراین ممکن است برنامه معیوب و خراب شود. این تباهی و خرابی برنامه می تواند خودش را در هر زمانی بعد از اینکه خسارت واقعی اتفاق افتاد، حتی ساعت ها یا روزهایی در آینده آشکار سازد.
http://java.sun.com/j2se/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html

همانطور که می دانید با اجرای تابع sleep ، استثناء InterruptedException رخ می دهد که با catch گرفتار می شود. حالا اگر به جای InterruptedException از Throwable استفاده کنیم، دیگر نخ نخواهد مُرد و از اسارت رها خواهد شد.
try
{
System.out.println(count);
Thread.sleep(2000);
}
catch (InterruptedException e)
{
System.out.println(e);
}

try
{
System.out.println(count);
Thread.sleep(2000);
}
catch(Throwable e)
{
System.out.println(e);
}همین موضوع را همراه با خروجی برنامه ای که از Throwable استفاده کرده است و نخ را از مرگ نجات داده است در برنامه واقع در آدرس http://barnamenevis.org/forum/showthread.php?t=197042 ببینید.

قله بلند
پنج شنبه 10 دی 1388, 17:47 عصر
یک راه حل جایگزین برای تابع stop پیدا کردم ولی قادر به کشتن نخ نیست. یعنی انگار نخ متوجه نمی شود که متغیر stop، نادرست شده است. برنامه را ببینید.
import java.lang.Runnable;
class Counter implements Runnable {
public int count = 1;
private volatile boolean stop = true;
public void run()
{
while (stop && count < 3)
{
try
{
System.out.println(count+" "+stop);
Thread.sleep(2000);
}
catch (InterruptedException e)
{
System.out.println("InterruptedException");
}
count++;
}
System.out.println("+");

if(!stop)
{
System.out.println("Detected Stop");
}
}
public void requestStop()
{
stop=false;
System.out.println("stop= "+stop);
}
}
public class B
{
public static void main(String args[]) throws Exception
{
Counter r = new Counter();
Thread t = new Thread(new Counter(),"CounterThread");
t.start();
Thread.sleep(1000);
//t.stop();//Counter Thread dead!
r.requestStop();
}
}اولاً باید چه کرد، ثانیاً محدوده نخ فقط دستورات درون تابع run است یا تمام دستورات کلاسی که واسط Runnable را اجرا می کند؟

قله بلند
جمعه 11 دی 1388, 16:53 عصر
سلام. قسمت آخر برنامه پست قبل را اینگونه اصلاح کنید تا نخ از بین برود و دیگر فعالیتی نداشته باشد.
public class B
{
public static void main(String args[]) throws Exception
{
Counter r = new Counter();
Thread t = new Thread(r,"CounterThread");
t.start();
Thread.sleep(1000);
r.requestStop();
}
}به اشتباهی که در پست قبل رخ داده بود دقت کنید:
public class B
{
public static void main(String args[]) throws Exception
{
Counter r = new Counter();
Thread t = new Thread(new Counter(),"CounterThread");//new Counter() was mistake
t.start();
Thread.sleep(1000);
r.requestStop();
}
}